Python数模笔记-NetworkX(3)条件最短路径
1、帶有條件約束的最短路徑問(wèn)題
最短路徑問(wèn)題是圖論中求兩個(gè)頂點(diǎn)之間的最短路徑問(wèn)題,通常是求最短加權(quán)路徑。
條件最短路徑,指帶有約束條件、限制條件的最短路徑。例如,頂點(diǎn)約束,包括必經(jīng)點(diǎn)或禁止點(diǎn)的限制;邊的約束,包括必經(jīng)路段或禁止路段;還包括無(wú)權(quán)路徑長(zhǎng)度的限制,即經(jīng)過(guò)幾步到達(dá)終點(diǎn)。進(jìn)一步地,還有雙目標(biāo)限制的最短路徑問(wèn)題,求最短距離中花費(fèi)最小的路線;交通限制條件下的最短路徑問(wèn)題,需要考慮轉(zhuǎn)向限制和延誤的約束。
求解帶有限制條件的最短路徑問(wèn)題,總體來(lái)說(shuō)可以分為兩類基本方法:一類是基于不帶限制條件的最短路徑算法,對(duì)求解過(guò)程中的每一條有效路徑,都用限制條件進(jìn)行判斷,如果滿足所有限制條件則繼續(xù),如果不滿足限制條件則放棄該路徑;另一類方法是基于具體問(wèn)題和選擇算法的特點(diǎn),將問(wèn)題轉(zhuǎn)化為有約束的規(guī)劃問(wèn)題來(lái)處理。
但是,如果使用 NetworkX 求解帶有限制條件的最短路徑問(wèn)題,采用這兩類方法都會(huì)有一些困難。原因在于前文所介紹的 NetworkX 提供的 Dijkstra 算法、Bellman-Ford 算法、Floyd 算法和啟發(fā)式算法 A* 都是封裝函數(shù),沒有提供設(shè)置約束條件的選項(xiàng)和接口,因此用戶不能把條件判斷語(yǔ)句加入這些封裝函數(shù)的程序內(nèi)部。這種問(wèn)題不僅存在于 Python 語(yǔ)言的 Network 工具包,對(duì)于其它計(jì)算機(jī)語(yǔ)言的工具包也是類似的:自己編程序費(fèi)時(shí)費(fèi)力,但可以根據(jù)需要修改和擴(kuò)展;直接調(diào)用工具包的算法函數(shù)非常方便,但不能進(jìn)行修改或擴(kuò)展。
不過(guò),NetworkX 可以生成兩個(gè)頂點(diǎn)之間的所有簡(jiǎn)單路徑,而且可以獲得所有簡(jiǎn)單路徑的邊的列表。利用簡(jiǎn)單路徑算法,可以通過(guò)對(duì)約束條件的判斷來(lái)求解帶有頂點(diǎn)約束和邊約束的最短路徑問(wèn)題。
歡迎關(guān)注 Youcans 原創(chuàng)系列,數(shù)模筆記每周更新
Python數(shù)模筆記-PuLP庫(kù)
Python數(shù)模筆記-StatsModels統(tǒng)計(jì)回歸
Python數(shù)模筆記-Sklearn
Python數(shù)模筆記-NetworkX
Python數(shù)模筆記-模擬退火算法
2、問(wèn)題案例:螞蟻的最優(yōu)路徑分析
蟻巢有若干個(gè)儲(chǔ)藏間(圖中圓圈表示),儲(chǔ)藏間之間有路徑相連(路徑拓?fù)浣Y(jié)構(gòu)如圖所示)。該圖為無(wú)向圖,路徑通行的花費(fèi)如圖中線路上的數(shù)字所示,路徑正反方向通行的花費(fèi)相同。要求從起點(diǎn) N0 到終點(diǎn) N17 的最優(yōu)路徑,并需要滿足限制條件:
- 需要盡可能以最少的花費(fèi)到達(dá)終點(diǎn);
- 必須經(jīng)過(guò)圖中的綠色節(jié)點(diǎn);
- 必須經(jīng)過(guò)圖中的兩段綠色路段;
- 必須避開圖中的紅色路段。
說(shuō)明:本案例出自西安郵電大學(xué)第12屆數(shù)學(xué)建模競(jìng)賽賽題,本文進(jìn)行了改編。
3、NetworkX 求解帶有條件約束的最短路徑問(wèn)題
3.1 圖的創(chuàng)建和可視化
Python 例程(NetworkX)
# networkX_E3.py # Demo of shortest path with NetworkX # Copyright 2021 YouCans, XUPT # Crated:2021-05-20import matplotlib.pyplot as plt # 導(dǎo)入 Matplotlib 工具包 import networkx as nx # 導(dǎo)入 NetworkX 工具包# 問(wèn)題 1:螞蟻的最優(yōu)路徑分析(西安郵電大學(xué)第12屆數(shù)學(xué)建模競(jìng)賽B題)gAnt = nx.Graph() # 創(chuàng)建:空的 無(wú)向圖 gAnt.add_weighted_edges_from([(0,1,3),(0,2,1),(0,3,1),(1,2,1),(1,4,1),(1,9,4),(2,3,1),(2,4,2),(2,5,1),(3,5,2),(3,6,2),(3,7,1),(4,5,1),(4,9,1),(5,6,1),(5,9,3),(5,10,1),(5,12,3),(6,7,1),(6,8,2),(6,12,2),(6,13,4),(6,14,3),(7,8,1),(8,14,1),(8,15,3),(9,10,1),(9,11,1),(10,11,1),(10,12,2),(11,12,1),(11,16,1),(12,13,2),(12,16,1),(13,14,1),(13,15,2),(13,16,2),(13,17,1),(14,15,1),(15,17,4),(16,17,1)]) # 向圖中添加多條賦權(quán)邊: (node1,node2,weight)pos={0:(1,8),1:(4,12),2:(4,9),3:(4,6),4:(8,11),5:(9,8), # 指定頂點(diǎn)位置6:(11,6),7:(8,4),8:(12,2),9:(12,13),10:(15,11),11:(18,13),12:(19,9),13:(22,6),14:(18,4),15:(21,2),16:(22,11),17:(28,8)} nx.draw(gAnt, pos, with_labels=True, alpha=0.8) labels = nx.get_edge_attributes(gAnt,'weight') nx.draw_networkx_edge_labels(gAnt,pos,edge_labels=labels, font_color='c') # 顯示權(quán)值 nx.draw_networkx_nodes(gAnt,pos,nodelist=[0,17],node_color='yellow') # 設(shè)置頂點(diǎn)顏色 nx.draw_networkx_nodes(gAnt,pos,nodelist=[7,12],node_color='lime') # 設(shè)置頂點(diǎn)顏色 nx.draw_networkx_edges(gAnt,pos,edgelist=[(2,4),(13,14)],edge_color='lime',width=2.5) # 設(shè)置邊的顏色 nx.draw_networkx_edges(gAnt,pos,edgelist=[(11,12)],edge_color='r',width=2.5) # 設(shè)置邊的顏色 plt.show()運(yùn)行結(jié)果
本段程序繪制網(wǎng)絡(luò)圖,包括頂點(diǎn)、邊、邊的權(quán)值,特殊頂點(diǎn)和特殊邊的顏色設(shè)置。
程序說(shuō)明
3.2 無(wú)限制條件的最短路徑
程序說(shuō)明
Python 例程(NetworkX)
# 兩個(gè)指定頂點(diǎn)之間的最短加權(quán)路徑 minWPath1 = nx.dijkstra_path(gAnt, source=0, target=17) # 頂點(diǎn) 0 到 頂點(diǎn) 17 的最短加權(quán)路徑 # 兩個(gè)指定頂點(diǎn)之間的最短加權(quán)路徑的長(zhǎng)度 lMinWPath1 = nx.dijkstra_path_length(gAnt, source=0, target=17) #最短加權(quán)路徑長(zhǎng)度 print("\n問(wèn)題1: 無(wú)限制條件") print("S 到 E 的最短加權(quán)路徑: ", minWPath1) print("S 到 E 的最短加權(quán)路徑長(zhǎng)度: ", lMinWPath1)運(yùn)行結(jié)果
問(wèn)題1: 無(wú)限制條件 S 到 E 的最短加權(quán)路徑: [0, 2, 5, 10, 11, 16, 17] S 到 E 的最短加權(quán)路徑長(zhǎng)度: 63.3 限制條件:禁止點(diǎn)或禁止邊
程序說(shuō)明
Python 例程
# 2. 限制條件:禁止點(diǎn)或禁止邊 # 解決方案:從圖中刪除禁止頂點(diǎn)或禁止邊 gAnt.remove_nodes_from([5]) # 通過(guò)頂點(diǎn)標(biāo)簽 5 刪除頂點(diǎn) gAnt.remove_edge(13,17) # 刪除邊 (13,17) minWPath2 = nx.dijkstra_path(gAnt, source=0, target=17) # 頂點(diǎn) 0 到 頂點(diǎn) 17 的最短加權(quán)路徑 lMinWPath2 = nx.dijkstra_path_length(gAnt, source=0, target=17) #最短加權(quán)路徑長(zhǎng)度 print("\n問(wèn)題2: 禁止點(diǎn)或禁止邊的約束") print("S 到 E 的最短加權(quán)路徑: ", minWPath2) print("S 到 E 的最短加權(quán)路徑長(zhǎng)度: ", lMinWPath2)運(yùn)行結(jié)果
問(wèn)題2: 禁止點(diǎn)或禁止邊的約束 S 到 E 的最短加權(quán)路徑: [0, 3, 6, 12, 16, 17] S 到 E 的最短加權(quán)路徑長(zhǎng)度: 73.4 限制條件:一個(gè)必經(jīng)點(diǎn)
程序說(shuō)明
Python 例程
# 3. 限制條件:一個(gè)必經(jīng)點(diǎn) # 解決方案:分解為兩個(gè)問(wèn)題,問(wèn)題 1 為起點(diǎn)N0至必經(jīng)點(diǎn)N6,問(wèn)題 2 為必經(jīng)點(diǎn)N6至終點(diǎn)N17 minWPath3a = nx.dijkstra_path(gAnt, source=0, target=6) # N0 到 N6 的最短加權(quán)路徑 lMinWPath3a = nx.dijkstra_path_length(gAnt, source=0, target=6) # 最短加權(quán)路徑長(zhǎng)度 minWPath3b = nx.dijkstra_path(gAnt, source=6, target=17) # N6 到 N17 的最短加權(quán)路徑 lMinWPath3b = nx.dijkstra_path_length(gAnt, source=6, target=17) # 最短加權(quán)路徑長(zhǎng)度 minWPath3a.extend(minWPath3b[1:]) # 拼接 minWPath3a、minWPath3b 并去重 N7 print("\n問(wèn)題3: 一個(gè)必經(jīng)點(diǎn)的約束") print("S 到 E 的最短加權(quán)路徑: ", minWPath3a) print("S 到 E 的最短加權(quán)路徑長(zhǎng)度: ", lMinWPath3a+lMinWPath3b)運(yùn)行結(jié)果
問(wèn)題3: 一個(gè)必經(jīng)點(diǎn)的約束 S 到 E 的最短加權(quán)路徑: [0, 3, 6, 12, 16, 17] S 到 E 的最短加權(quán)路徑長(zhǎng)度: 73.5 限制條件:多個(gè)必經(jīng)點(diǎn)(方案一)
程序說(shuō)明
Python 例程
# 4. 限制條件:多個(gè)必經(jīng)點(diǎn) (N7,N15) # 解決方案:遍歷從起點(diǎn)到終點(diǎn)的簡(jiǎn)單路徑,求滿足必經(jīng)點(diǎn)條件的最短路徑 minWPath4 = min([path # 返回 key 為最小值的 pathfor path in nx.all_simple_paths(gAnt, 0, 17) # gAnt 中所有起點(diǎn)為0、終點(diǎn)為17的簡(jiǎn)單路徑if all(n in path for n in (7, 15))], # 滿足路徑中包括頂點(diǎn) N7,N15key=lambda x: sum(gAnt.edges[edge]['weight'] for edge in nx.utils.pairwise(x))) # key 為加權(quán)路徑長(zhǎng)度 lenPath = sum(gAnt.edges[edge]['weight'] for edge in nx.utils.pairwise(minWPath4)) # 求指定路徑的加權(quán)路徑長(zhǎng)度 print("\n問(wèn)題4: 多個(gè)必經(jīng)點(diǎn)的約束") print("S 到 E 的最短加權(quán)路徑: ", minWPath4) print("S 到 E 的最短加權(quán)路徑長(zhǎng)度: ", lenPath)運(yùn)行結(jié)果
問(wèn)題4: 多個(gè)必經(jīng)點(diǎn)的約束 S 到 E 的最短加權(quán)路徑: [0, 3, 7, 8, 14, 15, 13, 17] S 到 E 的最短加權(quán)路徑長(zhǎng)度: 83.6 限制條件:多個(gè)必經(jīng)點(diǎn)(方案二)
程序說(shuō)明
Python 例程
# 5. 限制條件:多個(gè)必經(jīng)點(diǎn) (N7,N15) # 解決方案:遍歷從起點(diǎn)到終點(diǎn)的簡(jiǎn)單路徑,求滿足必經(jīng)點(diǎn)條件的最短路徑 lMinWPath5 = minWPath5 = 1e9 for path in nx.all_simple_paths(gAnt, 0, 17):if all(n in path for n in (7,15)): # 滿足路徑中包括頂點(diǎn) N7,N15lenPath = sum(gAnt.edges[edge]['weight'] for edge in nx.utils.pairwise(path))if lenPath < lMinWPath5:lMinWPath5 = lenPathminWPath5 = path print("\n問(wèn)題5: 多個(gè)必經(jīng)點(diǎn)的約束") print("S 到 E 的最短加權(quán)路徑: ", minWPath5) print("S 到 E 的最短加權(quán)路徑長(zhǎng)度: ", lMinWPath5)運(yùn)行結(jié)果
問(wèn)題5: 多個(gè)必經(jīng)點(diǎn)的約束 S 到 E 的最短加權(quán)路徑: [0, 3, 7, 8, 14, 15, 13, 17] S 到 E 的最短加權(quán)路徑長(zhǎng)度: 83.7 限制條件:必經(jīng)邊
程序說(shuō)明
Python 例程
# 6. 限制條件:必經(jīng)邊 (N2,N4), (N13,N14),必經(jīng)點(diǎn) N7,N12 # 解決方案:遍歷從起點(diǎn)到終點(diǎn)的簡(jiǎn)單路徑,求滿足必經(jīng)邊條件的最短路徑 gAnt.remove_edge(11,12) # 禁止邊 (11,12) lMinWPath6 = minWPath6 = 1e9 # 置初值 for path in nx.all_simple_paths(gAnt, 0, 17): # 所有起點(diǎn)為0、終點(diǎn)為17的簡(jiǎn)單路徑if all(n in path for n in (2,4,7,12,13,14)): # 滿足路徑中包括頂點(diǎn) N7,N12# 檢查 (N2,N4)p1 = path.index(2) # N2 的位置if (path[p1-1]!=4 and path[p1+1]!=4): continue # 判斷 N2~N4 是否相鄰# 檢查 (N13,N14)p2 = path.index(13) # # N13 的位置if (path[p2-1]!=14 and path[p2+1]!=14): continue # 判斷 N13~N14 是否相鄰lenPath = sum(gAnt.edges[edge]['weight'] for edge in nx.utils.pairwise(path))if lenPath < lMinWPath6:lMinWPath6 = lenPathminWPath6 = pathprint("\n問(wèn)題6: 多個(gè)必經(jīng)邊、必經(jīng)點(diǎn)的約束") print("S 到 E 的最短加權(quán)路徑: ", minWPath6) print("S 到 E 的最短加權(quán)路徑長(zhǎng)度: ", lMinWPath6)edgeList = [] for i in range(len(minWPath6)-1):edgeList.append((minWPath6[i],minWPath6[i+1])) nx.draw_networkx_edges(gAnt,pos,edgelist=edgeList,edge_color='m',width=4) # 設(shè)置邊的顏色 plt.show() # YouCans, XUPT運(yùn)行結(jié)果
問(wèn)題6: 多個(gè)必經(jīng)邊、必經(jīng)點(diǎn)的約束 S 到 E 的最短加權(quán)路徑: [0, 2, 4, 5, 6, 7, 8, 14, 13, 12, 16, 17] S 到 E 的最短加權(quán)路徑長(zhǎng)度: 13版權(quán)說(shuō)明:
本文內(nèi)容及例程為作者原創(chuàng),并非轉(zhuǎn)載書籍或網(wǎng)絡(luò)內(nèi)容。
本文中案例問(wèn)題來(lái)自:
YouCans 原創(chuàng)作品,如轉(zhuǎn)載需標(biāo)注原始鏈接。
Copyright 2021 YouCans, XUPT
Crated:2021-05-20
歡迎關(guān)注 Youcans 原創(chuàng)系列,數(shù)模筆記每周更新
Python數(shù)模筆記-PuLP庫(kù)(1)線性規(guī)劃入門
Python數(shù)模筆記-PuLP庫(kù)(2)線性規(guī)劃進(jìn)階
Python數(shù)模筆記-PuLP庫(kù)(3)線性規(guī)劃實(shí)例
Python數(shù)模筆記-StatsModels 統(tǒng)計(jì)回歸(1)簡(jiǎn)介
Python數(shù)模筆記-StatsModels 統(tǒng)計(jì)回歸(2)線性回歸
Python數(shù)模筆記-StatsModels 統(tǒng)計(jì)回歸(3)模型數(shù)據(jù)的準(zhǔn)備
Python數(shù)模筆記-StatsModels 統(tǒng)計(jì)回歸(4)可視化
Python數(shù)模筆記-Sklearn (1)介紹
Python數(shù)模筆記-Sklearn (2)聚類分析
Python數(shù)模筆記-Sklearn (3)主成分分析
Python數(shù)模筆記-Sklearn (4)線性回歸
Python數(shù)模筆記-Sklearn (5)支持向量機(jī)
Python數(shù)模筆記-NetworkX(1)圖的操作
Python數(shù)模筆記-NetworkX(2)最短路徑
Python數(shù)模筆記-NetworkX(3)條件最短路徑
Python數(shù)模筆記-模擬退火算法(1)多變量函數(shù)優(yōu)化
Python數(shù)模筆記-模擬退火算法(2)約束條件的處理
Python數(shù)模筆記-模擬退火算法(3)整數(shù)規(guī)劃問(wèn)題
Python數(shù)模筆記-模擬退火算法(4)旅行商問(wèn)題
總結(jié)
以上是生活随笔為你收集整理的Python数模笔记-NetworkX(3)条件最短路径的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【OpenCV 例程200篇】25. 图
- 下一篇: java产生字符函数_java生成字符串