阿里校招算法岗测试题——n个节点的完全图,每两个节点之间路经m条线的最短距离

本文介绍了一种用于设计学校接力跑大赛线路的算法,旨在为每个班级的学生找到恰好经过M条边的最短路径。该算法适用于由N个节点组成的完全图,考虑了重复边的情况,并提供了Python实现,时间复杂度约为O(N^3*log(M))。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

光明小学的小朋友们要举行一年一度的接力跑大赛了,但是小朋友们却遇到了一个难题:设计接力跑大赛的线路,你能帮助他们完成这项工作么?
光明小学可以抽象成一张有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

分析:

首先,假设从 i 到 j 经过(m-1)条边的最短距离已知,存储在last_opt[n][n]二维数组中。那么从 i 到 j 经过m条边的最短距离简化成:

dp_opt=min(last_opt [i] [x] + map [x] [j] )

经过m条边的最短路径只和最后一步的路径以及走(m-1)步的最短路径有关,map [x] [j] 表示最后一步,last_opt [i] [x] 表示从起点 i 走m-1 步到x的最短路径。

附上Python 3 代码,时间复杂度 O(n^3*(m-1))//我不会算时间复杂度呀,这里可能算错了

空间复杂度O(2*n*n)

def minPath(n,m,map):
    last_opt=[list(x) for x in map]#初始化
    dp_opt=[list(x) for x in map]#初始化
    for step in range(m-1):#只需要循环 m-1次
        for i in range(n):
            for j in range(n):
                temp = [last_opt[i][x] + map[x][j] for x in range(n) if map[x][j]!=0 and last_opt[i][x]!=0] #递推式转换 注意判断条件
                dp_opt[i][j] = min(temp)#取所有情况中的最小值
        last_opt=[list(x) for x in dp_opt]#拷贝以待下次循环
    return dp_opt


if __name__ == '__main__':
    n = int(input())
    m = int(input())
    x=input()
    map = []
    for i in range(n):
        map.append([int(x) for x in input().split()])
    res=minPath(n,m,map)
    for x in res:
        print(x)

来看看测试结果:

再来看看m=3的结果:

再来看看n=4 的结果:

因为道路是无向的,所以从 i 到 j 走m步的最短距离肯定和从 j 到 i 走m步的最短距离相等,所以输出一定是一个对称矩阵,如果不是对称的,一定是哪里逻辑出错了……

如果有人搜到这篇博客,然后复制我的代码上去,可能会发现代码测试通过率为0,那是因为要求的输出是数字,但是这里输出的dp_opt是一个列表,是带方括号的,和题目要求不符,记得自己改下代码,挨个输出就行了。

C++代码有空再写。

嘤嘤嘤,第一次自己做出来的动态规划题,虽然测试的时候没做出来……umm当自我安慰吧。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值