Floyd算法:
思路 :遍歷計算 i 點 經過 k 點 到 j 點 的最小路徑值 (動態規划思路)
缺點:時間復雜度高,不能解決負邊情況
輸入樣例:
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
輸出樣例:
1-->2:2
1-->3:5
1-->4:4
2-->1:9
2-->3:3
2-->4:4
3-->1:6
3-->2:8
3-->4:1
4-->1:5
4-->2:7
4-->3:10
#include <cstdio> #include <string.h> #include <iostream> #include <algorithm> #include <sstream> #include <math.h> #include <queue> using namespace std; const int inf=0x7fffff; const long long mod=1e9+7; const double PI=acos(-1); int n,m,start,end; int ans=9999999; bool vis[105]; int e[105][105]; void init(){ //初始化鄰接矩陣 for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j) e[i][j]=0; else e[i][j]=inf; } } } void Floyd(){ //思路:依此判斷 i 通過 k 到 j 的最短路 for(int k=1;k<=n;k++){ // k 經轉的節點 for(int i=1;i<=n;i++){ // i 每次的起點 for(int j=1;j<=n;j++){ // j 每次的終點 if(k==i&&k==j) continue; if(e[i][j]>e[i][k]+e[k][j]){ e[i][j]=e[i][k]+e[k][j]; } } } } } int main() { int x,y,value; cin>>n>>m; init(); for(int i=0;i<m;i++){ cin>>x>>y>>value; e[x][y]=value; } Floyd(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j) continue; cout<<i<<"-->"<<j<<":"<<e[i][j]<<endl; } } return 0; }
Dijkstra算法:
思路:依此找起點可達的點的最小值點。通過最小值點再訪問其他點。不斷更新最小距離。
測試數據:
6 9 1 (6個點9條邊 1為起點)
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
輸出數據:
1-->1:0
1-->2:1
1-->3:8
1-->4:4
1-->5:13
1-->6:17
#include <cstdio> #include <string.h> #include <iostream> #include <algorithm> #include <sstream> #include <math.h> #include <queue> using namespace std; const int inf=0x7fffff; const long long mod=1e9+7; const double PI=acos(-1); int n,m,start,end; int ans=9999999; bool vis[105]; int e[105][105]; void init(){ //初始化鄰接矩陣 for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j) e[i][j]=0; else e[i][j]=inf; //設 inf 為 ∞ 表示兩點不通 } } } void Dijkstra(int s){ //Dijkstra算法為單源最短路徑算法 s 為起點 int dis[n+1]; // dis 用來 記錄每次操作時 s 到每個點的最短路徑 int minp; // 記錄目前操作的最小距離點 int min=inf; for(int i=1;i<=n;i++){ //初始化最短距離數組 dis dis[i]=e[s][i]; } vis[s]=1; for(int i=1;i<=n;i++){ min=inf; for(int j=1;j<=n;j++){ //每次找dis數組里面最小未訪問過的值 if(min>dis[j]&&!vis[j]){ min=dis[j]; //min 表示此時未訪問過的最小距離 minp=j; //minj表示未訪問過的最小距離那個點 } } vis[minp]=1; //設置訪問 for(int v=1;v<=n;v++){ //每次訪問 此時與最小值點相連的點v if(e[minp][v]<inf){ //該點可達 if(dis[v]>dis[minp]+e[minp][v]){ //s直接到 v 的距離大於 s通過 最小值點到 v 的距離,則更新 dis[v]=dis[minp]+e[minp][v]; } } } } for(int i=1;i<=n;i++){ cout<<s<<"-->"<<i<<":"<<dis[i]<<endl; //遍歷 s 到 每個點的最小距離 } } int main() { int x,y,value,s; cin>>n>>m>>s; init(); for(int i=0;i<m;i++){ cin>>x>>y>>value; e[x][y]=value; } Dijkstra(s); //s 為起點 return 0; }
Bellman_Floyd算法:
思路:經過n-1次迭代,判斷每次迭代判斷能不能用u[i]-->v[i]
使源點到v[i]的最短路徑變短。
優點:可以解決帶負邊的問題。
輸入樣例:
5 5 1 (5個點 5條邊 起點1)
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3
輸出樣例:
0 -3 -1 2 4 (起點到各個點的最短路徑)
#include <cstdio> #include <string.h> #include <iostream> #include <algorithm> #include <sstream> #include <math.h> #include <vector> using namespace std; const int inf=999999;//0x7fffff const long long mod=1e9+7; const double PI=acos(-1); int n,m; int ans=9999999; bool vis[105]; int dis[105],u[105],v[105],w[105]; void Bellman_Floyd(int s){ memset(dis,inf,sizeof(dis)); //初始 dis最短路徑數組 為無窮 dis[s]=0; for(int k=1;k<=n-1;k++){ //迭代 n-1次 更新最短路徑表dis for(int j=1;j<=m;j++){ dis[v[j]]=min(dis[v[j]],dis[u[j]]+w[j]); //每次計算能不能由 u[i]到 v[i] 能不能使結果變小並更新 } } // bool ok=0; // for(int k=1;k<=m;k++){ // if(dis[v[k]]>dis[u[k]]+w[k]) ok=1; //檢測負權回路 // } } int main() { int x,y,s; cin>>n>>m>>s; for(int i=1;i<=m;i++){ cin>>u[i]>>v[i]>>w[i]; //u[i]邊起使點 v[i]邊指向點 w[i] 權值 } Bellman_Floyd(s); for(int i=1;i<=n;i++){ cout<<dis[i]<<" "; } return 0; }