阿里2019校招在线编程题

题目
光明小学的小朋友们要举行一年一度的接力跑大赛了,但是小朋友们却遇到了一个难题:设计接力跑大赛的线路,你能帮助他们完成这项工作么?
光明小学可以抽象成一张有N个节点的图,每两点间都有一条道路相连。光明小学的每个班都有M个学生,所以你要为他们设计出一条恰好经过M条边的路径。
光明小学的小朋友们希望全盘考虑所有的因素,所以你需要把任意两点间经过M条边的最短路径的距离输出出来以供参考。

你需要设计这样一个函数:
res[][] Solve( N, M, map[][]);
注意:map必然是N * N的二维数组,且map[i][j] == map[j][i],map[i][i] == 0,-1e8 <= map[i][j] <= 1e8。(道路全部是无向边,无自环)2 <= N <= 100, 2 <= M <= 1e6。要求时间复杂度控制在O(N^3*log(M))。

map数组表示了一张稠密图,其中任意两个不同节点i,j间都有一条边,边的长度为map[i][j]。N表示其中的节点数。
你要返回的数组也必然是一个N * N的二维数组,表示从i出发走到j,经过M条边的最短路径
你的路径中应考虑包含重复边的情况。

样例:

N = 3
M = 2
map = {
{0, 2, 3},
{2, 0, 1},
{3, 1, 0}
}

输出结果result为:
result = {
{4, 4, 3},
{4, 2, 5},
{3, 5, 2}
}

输入样例:

3
2
3 3
0 2 3
2 0 1
3 1 0

输出样例:

[[4, 4, 3],

[4, 2, 5],

[3, 5, 2]]

代码思路:首先很气,编出主程序的时候,在输入数据处理上,遇到很白痴的问题,结果没有来得及改就胶卷了,完成之后花了2min改好,上传上来
采用动态规划的方式来做

import numpy  as np

def Solve(maps,M):
    '''
    由N个节点两两连接组成路径,选取从节点i->节点j之间的最短M条路径

    param:
        maps:二维数组,由两两节点之间的路径长度组成
        M:表示所经过的路径个数
    '''    
    '''
    输入校验
    '''    
    if not isinstance(maps,(list,np.ndarray)): 
        raise ValueError('输入参数maps数据类型必须是list或者numpy.array')

    if len(maps.shape) != 2:
        raise ValueError('输入参数maps为二维数组')

    if maps.shape[0] != maps.shape[1]:
        raise ValueError('输入二维数组maps行数和列数要求一致')

    #计算节点的个数
    N = maps.shape[0]    

    if N<2 or N>100:
        raise ValueError('输入二维数组maps行数必须在2~100之间')

    if M<2 or M>1E6:
        raise ValueError('输入参数N的值必须在2~1e6之间')

    #输入二维数组数值校验
    for i in range(N):
        for j in range(i,N):
            if maps[i][j] != maps[j][i]:
                raise ValueError('输入二维数组maps必须是对称的')
            if maps[i][j] < -1e8 or maps[i][j] > 1e8:
                raise ValueError('二维数组maps的元素值必须在-1e8~1e8之间')
            if i==j:
                if maps[i][j] != 0:
                    raise ValueError('二维数组maps的对角元素值必须是0')


    #用于保存i->j的路径值
    res = np.zeros_like(maps)

    #计算节点i->j的最短路径
    for i in range(N):
        for j in range(i,N):
            res[i][j] = MinPath(maps,M,i,j)
            res[j][i] = res[i][j]
    return res

def  MinPath(maps,M,i,j):
    '''
    计算i->j的最短路径
    '''
    #递归终止条件
    if M == 1:
        return maps[i][j]
    '''计算i->j的最短路径'''
    N = maps.shape[0]   
    #用于保存i->j的可能路径长度
    length = np.zeros(N)    
    #遍历从k->j的最短路径
    for k in range(N):
        if k != i and k != j:
            #k->j的M-1条最短路径 + i->k的一条路径
            length[k] = MinPath(maps,M-1,k,j) + maps[i][k]

    #进行排序,过滤掉为0的值
    length = np.sort(length)
    for  i in length:
        if i != 0:
            return i

if __name__ == '__main__':
    N = int(input().strip())
    M = int(input().strip())
    shapes = [int(c) for c in input().strip().split()]
    #print(shapes)
    maps = []
    for i in range(N):
        n = [int(c) for c in input().strip().split()]
        maps.append(n)
    #print(maps)
    maps = np.array(maps)
    result = Solve(maps,M)
    print(result)  
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值