圖論:Ford 演算法 求最短路徑
阿新 • • 發佈:2022-05-10
Ford 演算法 求最短路徑
先構建鄰接表陣列和初始化鄰接關係
int v1[maxn],v2[maxn],w[maxn];//記錄起點終點和權值
for(int i=1;i<=m;++i)
{
cin>>u>>v>>val;
v1[i]=u;
v2[i]=v;
w[i]=val;
}
構建一維陣列d,記錄距離出發點的距離,d[出發點]初始化為0,自己和自己的距離為0,其他點和出發點的d先初始化為oo,並且構建pre陣列,便於遞迴輸出最短路徑。出發點的前驅結點設為0,代表出發點沒有前驅結點,也是一會遞迴輸出路徑的退出條件。
int d[maxn],pre[maxn];//記錄距離出發點的距離 和最短路徑的前驅結點
for(int i=0;i<=n;++i)d[i]=0x7fffff;//先初始化為oo 很大的值
d[s]=0;//自己到自己的距離為0;
pre[s]=0;
核心演算法程式碼就是一個二維陣列,外層迴圈n-1次,內層迴圈m次,內層是迴圈m個鄰接關係,每次更新d,外層迴圈n-1次,是剛好迴圈n-1次可以把所有點到起點的最短距離更新完。內層迴圈中,定義起點為u,終點為v,進行兩個if判斷,①:如果d[u]+邊權<d[v]就更新d[v],就是更新v到起點的距離,②:如果d[v]+邊權<d[u] 就更新起點到u的距離。注意兩次更新中,如果有更新,都要改變pre陣列,像第一次if 如果更新,就說明起點到u 再到 v的路徑更短,所以 v的前驅是u 更新pre[v]=u,後面同理。
for(int i=1;i<=n-1;++i)//最多n-1次
for(int j=1;j<=m;++j)
{
u=v1[j],v=v2[j];
if(d[u]+w[j]<d[v])
{
d[v]=d[u]+w[j];
pre[v]=u;
}
if(d[v]+w[j]<d[u])
{
d[u]=d[v]+w[j];
pre[u] =v;
}
}
輸出路徑的遞迴函式:
void print(int i)//遞迴輸出路徑程式碼
{
if(pre[i])
print(pre[i]);
cout<<i<<" ";
}
完整程式碼:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=100;
int v1[maxn],v2[maxn],w[maxn];//記錄起點終點和權值
int d[maxn],pre[maxn];//記錄距離出發點的距離 和最短路徑的前驅結點
int n,m,s;//n個結點 m條邊 s為出發點
int u,v,val;//起點和終點
void print(int i)//遞迴輸出路徑程式碼
{
if(pre[i])
print(pre[i]);
cout<<i<<" ";
}
int main()
{
cin>>n>>m>>s;
for(int i=0;i<=n;++i)d[i]=0x7fffff;//先初始化為oo 很大的值
for(int i=1;i<=m;++i)
{
cin>>u>>v>>val;
v1[i]=u;
v2[i]=v;
w[i]=val;
}
d[s]=0;//自己到自己的距離為0;
pre[s]=0;
for(int i=1;i<=n-1;++i)//最多n-1次
for(int j=1;j<=m;++j)
{
u=v1[j],v=v2[j];
if(d[u]+w[j]<d[v])
{
d[v]=d[u]+w[j];
pre[v]=u;
}
if(d[v]+w[j]<d[u])
{
d[u]=d[v]+w[j];
pre[u]=v;
}
}
for (int i = 1; i <= n; ++i)
{
cout << d[i] << endl;
print(i);
}
return 0;
}