程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

2019阿里校招测评题,光明小学完全图最短路径问题(python实现)

题目:光明小学的小朋友们要举行一年一度的接力跑大赛了,但是小朋友们却遇到了一个难题:设计接力跑大赛的线路,你能帮助他们完成这项工作么?
光明小学可以抽象成一张有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条边的最短路径
你的路径中应考虑包含重复边的情况。

一 、求解

先来说一下求解这一题的思路,这个问题的本质就是M步无向图的最短路径遍历,一般求解最短路径问题,我们首先想到的就是采用递归实现。

已知有N个节点,求解从节点i到节点j之间的M步的最短路径问题,我们可以把M步分解成1步和M-1步:

1、假设存在节点k,且k节点不同于节点i,节点j,第一步求解节点i到节点k之间的1步最短路径

2、剩下M-1步,可以看做求解节点k到节点j之间的M-1步最短路径问题

3、当k取不同值时,我们会得到多个距离值,选取最小的一个距离值

复制代码
# -*- coding: utf-8 -*-
"""
Created on Fri Aug  3 08:54:35 2018

@author: zy
"""

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__':
    #maps = np.array([[0,2,3],[2,0,1],[3,1,0]])
    maps = np.array([[0,2,3,4],
                     [2,0,1,3],
                     [3,1,0,2],
                     [4,3,2,0]
            ])
    M = 3
    result = Solve(maps,M)
    print(result)
        
复制代码

 二、时间复杂度分析

 我们来分析一下该算法的时间复杂度。

先来分析一下递归函数MinPath(maps,M,i,j):

1、函数的规模为M

2、当规模是1时,函数结束

3、假设T(M)表示规模为M的问题所需要的步骤数

算法的递归方程为:T(M) = (N-2)T(M - 1) +3N+6

注释:3N+6表示规模毎减少一次,所做的步骤数

  1. if M==1:                      1次
  2. N=maps.shape[0]       1次
  3. length = np.zeros(N)   1次
  4. for k in range(N):        N次

  5. if k != i and k != j:        N次
  6. + maps[i][k]                 当i==j时 N-1次,否则N-2次  我们取N-2次
  7. length = np.sort(length)  1次
  8. 最后的for循环             2次或者4次  我们取4次  

迭代展开:T(M) = (N-2)T(M - 1) + 3N+6

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(4122)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示