圖論_最短路徑
Floyd算法:
用鄰接矩陣保存原圖,時間復雜度O(N^3),空間復雜度O(N^2),N為圖中節點個數。
一般情況下,被要求解圖的大小不超過200個結點,當圖使用鄰接矩陣表示時更為方便,否則要註意轉換。
因為算法完成後,圖中所有結點間的最短路徑都將被確定,所以其較適用於全源最短路徑長度問題。
for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(ans[i][k]==無窮||ans[k][j]==無窮) continue;if(ans[i][j]==無窮||ans[i][k]+ans[k][j]<ans[i][j]) ans[i][j]=ans[i][k]+ans[k][j]; } } }
例5.5 最短路(1447)
題目描述:在每年的校賽裏,所有進入決賽的同學都會獲得一件很漂亮的t-shirt。但是每當我們的工作人員把上百件的衣服從商店運回到賽場的時候,卻是非常累的!所以現在他們想要尋找最短的從商店到賽場的路線,你可以幫助他們嗎?
輸入:輸入包括多組數據。每組數據第一行是兩個整數N、M(N<=100,M<=10000),N表示成都的大街上有幾個路口,標號為1的路口是商店所在地,標號為N的路口是賽場所在地,M則表示在成都有幾條路。N=M=0表示輸入結束。接下來M行,每行包括3個整數A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A與路口B之間有一條路,我們的工作人員需要C分鐘的時間走過這條路。輸入保證至少存在1條商店到賽場的路線。當輸入為兩個0時,輸入結束。
- 輸出:對於每組輸入,輸出一行,表示工作人員從商店走到賽場的最短時間。
樣例輸入: 2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0 樣例輸出: 3 2
#include<stdio.h> using namespace std; int ans[101][101]; int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ if(n==0&&m==0) break; for(int i=1;i<=n;i++){for(int j=1;j<=n;j++) ans[i][j]==-1; ans[i][i]=0; } while(m--){ int a,b,c; scanf("%d%d%d",&a,&b,&c); ans[a][b]=c; ans[b][a]=c; } for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(ans[i][k]==-1||ans[k][j]==-1) continue; if(ans[i][j]==-1||ans[i][k]+ans[k][j]<ans[i][j]) ans[i][j]=ans[i][k]+ans[k][j]; } } } printf("%d\n",ans[1][n]); } return 0; }
Dijkstra算法:
用鄰接鏈表或鄰接矩陣保存,只能求得某特定結點到其他所有結點的最短路徑長度,即單源最短路徑問題。
算法流程:
(1)初始化,集合K中加入結點1,結點1到結點1最短距離為0,到其他結點為無窮(或不確定)。
(2)遍歷與集合K中結點直接相鄰的邊(U,V,C),其中U屬於集合K,V不屬於集合K,計算由結點1出發按照已經得到的最短路到達U,再由U經過該邊到達V時的路徑長度。比較所有與集合K中結點直接相鄰的非集合K結點該路徑長度,其中路徑長度最小的結點被確定為下一個最短路徑確定的結點,其最短路徑長度即為這個路徑長度,最後將該結點加入集合K。
(3)若集合K中已經包含了所有的點,算法結束;否則重復步驟(2)。
下面重寫例4.5:
#include<stdio.h> #include<vector> using namespace std; struct E{ int next; int c; }; vector<E> edge[101]; bool mark[101]; int Dis[101]; int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ if(n==0&&m==0) break; for(int i=1;i<=n;i++) edge[i].clear(); while(m--){ int a,b,c; scanf("%d%d%d",&a,&b,&c); E tmp; tmp.c=c; tmp.next=b; edge[a].push_back(tmp); tmp.next=a; edge[b].push_back(tmp); } for(int i=1;i<=n;i++){ mark[i]=false; Dis[i]=-1; } Dis[1]=0; mark[1]=true; int newP=1; for(int i=1;i<n;i++){ for(int j=0;j<edge[newP].size();j++){//更新Dis int t=edge[newP][j].next; int c=edge[newP][j].c; if(mark[t]) continue; if(Dis[t]>Dis[newP]+c||Dis[t]==-1) Dis[t]=Dis[newP]+c; } int min=123123123; for(int j=1;j<=n;j++){//找newP if(mark[j]) continue; if(Dis[j]==-1) continue; if(Dis[j]<min){ min=Dis[j]; newP=j; } } mark[newP]=true; } printf("%d\n",Dis[n]); } return 0; }
圖論_最短路徑