python笔试题奥特曼打怪兽_2019阿里校招测评题,光明小学完全图最短路径问题(python实现)...
題目:光明小學(xué)的小朋友們要舉行一年一度的接力跑大賽了,但是小朋友們卻遇到了一個(gè)難題:設(shè)計(jì)接力跑大賽的線路,你能幫助他們完成這項(xiàng)工作么?
光明小學(xué)可以抽象成一張有N個(gè)節(jié)點(diǎn)的圖,每?jī)牲c(diǎn)間都有一條道路相連。光明小學(xué)的每個(gè)班都有M個(gè)學(xué)生,所以你要為他們?cè)O(shè)計(jì)出一條恰好經(jīng)過(guò)M條邊的路徑。
光明小學(xué)的小朋友們希望全盤(pán)考慮所有的因素,所以你需要把任意兩點(diǎn)間經(jīng)過(guò)M條邊的最短路徑的距離輸出出來(lái)以供參考。
你需要設(shè)計(jì)這樣一個(gè)函數(shù):
res[][] Solve( N, M, map[][]);
注意:map必然是N * N的二維數(shù)組,且map[i][j] == map[j][i],map[i][i] == 0,-1e8 <= map[i][j] <= 1e8。(道路全部是無(wú)向邊,無(wú)自環(huán))2 <= N <= 100, 2 <= M <= 1e6。要求時(shí)間復(fù)雜度控制在O(N^3*log(M))。
map數(shù)組表示了一張稠密圖,其中任意兩個(gè)不同節(jié)點(diǎn)i,j間都有一條邊,邊的長(zhǎng)度為map[i][j]。N表示其中的節(jié)點(diǎn)數(shù)。
你要返回的數(shù)組也必然是一個(gè)N * N的二維數(shù)組,表示從i出發(fā)走到j(luò),經(jīng)過(guò)M條邊的最短路徑
你的路徑中應(yīng)考慮包含重復(fù)邊的情況。
一 、求解
先來(lái)說(shuō)一下求解這一題的思路,這個(gè)問(wèn)題的本質(zhì)就是M步無(wú)向圖的最短路徑遍歷,一般求解最短路徑問(wèn)題,我們首先想到的就是采用遞歸實(shí)現(xiàn)。
已知有N個(gè)節(jié)點(diǎn),求解從節(jié)點(diǎn)i到節(jié)點(diǎn)j之間的M步的最短路徑問(wèn)題,我們可以把M步分解成1步和M-1步:
1、假設(shè)存在節(jié)點(diǎn)k,且k節(jié)點(diǎn)不同于節(jié)點(diǎn)i,節(jié)點(diǎn)j,第一步求解節(jié)點(diǎn)i到節(jié)點(diǎn)k之間的1步最短路徑
2、剩下M-1步,可以看做求解節(jié)點(diǎn)k到節(jié)點(diǎn)j之間的M-1步最短路徑問(wèn)題
3、當(dāng)k取不同值時(shí),我們會(huì)得到多個(gè)距離值,選取最小的一個(gè)距離值
#-*- coding: utf-8 -*-
"""Created on Fri Aug 3 08:54:35 2018
@author: zy"""
importnumpy as npdefSolve(maps,M):'''由N個(gè)節(jié)點(diǎn)兩兩連接組成路徑,選取從節(jié)點(diǎn)i->節(jié)點(diǎn)j之間的最短M條路徑
param:
maps:二維數(shù)組,由兩兩節(jié)點(diǎn)之間的路徑長(zhǎng)度組成
M:表示所經(jīng)過(guò)的路徑個(gè)數(shù)'''
'''輸入校驗(yàn)'''
if notisinstance(maps,(list,np.ndarray)):raise ValueError('輸入?yún)?shù)maps數(shù)據(jù)類型必須是list或者numpy.array')if len(maps.shape) != 2:raise ValueError('輸入?yún)?shù)maps為二維數(shù)組')if maps.shape[0] != maps.shape[1]:raise ValueError('輸入二維數(shù)組maps行數(shù)和列數(shù)要求一致')#計(jì)算節(jié)點(diǎn)的個(gè)數(shù)
N =maps.shape[0]if N<2 or N>100:raise ValueError('輸入二維數(shù)組maps行數(shù)必須在2~100之間')if M<2 or M>1E6:raise ValueError('輸入?yún)?shù)N的值必須在2~1e6之間')#輸入二維數(shù)組數(shù)值校驗(yàn)
for i inrange(N):for j inrange(i,N):if maps[i][j] !=maps[j][i]:raise ValueError('輸入二維數(shù)組maps必須是對(duì)稱的')if maps[i][j] < -1e8 or maps[i][j] > 1e8:raise ValueError('二維數(shù)組maps的元素值必須在-1e8~1e8之間')if i==j:if maps[i][j] !=0:raise ValueError('二維數(shù)組maps的對(duì)角元素值必須是0')#用于保存i->j的路徑值
res =np.zeros_like(maps)#計(jì)算節(jié)點(diǎn)i->j的最短路徑
for i inrange(N):for j inrange(i,N):
res[i][j]=MinPath(maps,M,i,j)
res[j][i]=res[i][j]returnresdefMinPath(maps,M,i,j):'''計(jì)算i->j的最短路徑'''
#遞歸終止條件
if M == 1:returnmaps[i][j]'''計(jì)算i->j的最短路徑'''N=maps.shape[0]#用于保存i->j的可能路徑長(zhǎng)度
length =np.zeros(N)#遍歷從k->j的最短路徑
for k inrange(N):if k != i and k !=j:#k->j的M-1條最短路徑 + i->k的一條路徑
length[k] = MinPath(maps,M-1,k,j) +maps[i][k]#進(jìn)行排序,過(guò)濾掉為0的值
length =np.sort(length)for i inlength:if i !=0:returniif __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= 3result=Solve(maps,M)print(result)
二、時(shí)間復(fù)雜度分析
我們來(lái)分析一下該算法的時(shí)間復(fù)雜度。
先來(lái)分析一下遞歸函數(shù)MinPath(maps,M,i,j):
1、函數(shù)的規(guī)模為M
2、當(dāng)規(guī)模是1時(shí),函數(shù)結(jié)束
3、假設(shè)T(M)表示規(guī)模為M的問(wèn)題所需要的步驟數(shù)
算法的遞歸方程為:T(M) = (N-2)T(M - 1) +3N+6
注釋:3N+6表示規(guī)模毎減少一次,所做的步驟數(shù)
if M==1: 1次
N=maps.shape[0] 1次
length = np.zeros(N) 1次
for k in range(N): N次
if k != i and k != j: N次
+maps[i][k] 當(dāng)i==j時(shí) N-1次,否則N-2次 我們?nèi)-2次
length =np.sort(length) 1次
最后的for循環(huán) 2次或者4次 我們?nèi)?次
迭代展開(kāi):T(M) = (N-2)T(M - 1) + 3N+6
=(N-2)[(N-2)T(M-2) + 3N + 6] + 3N+6
=(N-2)2T(M-2) + (N-2)(3N+6) + 3N+6
=(N-2)3T(M-3) + (N-2)2(3N+6) + (N-2)(3N+6) + 3N+6
=....
=(N-2)(M-1) + (N-2)(M-2)(3N+6)+...+3N+6
=(N-2)(M-1) + [(N-2)(M-1)(3N+6) - 3N-6]/(N-3)
= O((N-2)(M-1))
Solve函數(shù)中遞歸函數(shù)循環(huán)的次數(shù)為N(1+N)/2,所以算法的復(fù)雜度為O(N2(N-2)(M-1))。并沒(méi)有滿足題目的要求,更好的求解方法我還沒(méi)有想到,有了解的大佬可以告訴小弟。
參考文章:
總結(jié)
以上是生活随笔為你收集整理的python笔试题奥特曼打怪兽_2019阿里校招测评题,光明小学完全图最短路径问题(python实现)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 交叉熵理解
- 下一篇: 最基础的python自动化测试(基础篇)