圖論演算法----最短路徑Floyed演算法和Dijkstra演算法詳解
阿新 • • 發佈:2019-02-11
一、題目描述
最短路徑問題(floyed.cpp & dijkstra.cpp)
題目描述
平面上有n個點(n<=100),每個點的座標均在-10000~10000之間。其中的一些點之間有連線。若有連線,則表示可從一個點到達另一個點,即兩點間有通路,通路的距離為兩點間的直線距離。現在的任務是找出從一點到另一點之間的最短路徑。
輸入
第1行:1個整數n
第2..n+1行:每行2個整數x和y,描述了一個點的座標
第n+2行:1個整數m,表示圖中連線的數量
接下來有m行,每行2個整數i和j,表示第i個點和第j個點之間有連線
最後1行:2個整數s和t,分別表示源點和目標點
輸出
第1行:1個浮點數,表示從s到t的最短路徑長度,保留2位小數
樣例輸入
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5
樣例輸出
3.41
二、分析
1、Floyed演算法O(n³) 我們先對輸入的資料進行初始化:floyed演算法其實就是3個for迴圈,用i、j、k三個迴圈變數來列舉每一個點。用k來列舉中轉點,i、j來列舉i到j的點。 如果dis[i][k]+dis[k][j]<dis[i][j],則dis[i][j]=dis[i][k]+dis[k][j]。就是 i 到 k 的距離與 k 到 j 的距離的和,小於 i 到 j 的距離,就把dis[i][j]變成 i 到 k 的距離與 k 到 j 的距離 的和。<span style="font-size:18px;">#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; double dis[105][105];//dis[i][j]表示點i到點j的最短路徑長度 int zb[105][2];//座標 int main() { //freopen("floyed.in","r",stdin); //freopen("floyed.out","w",stdout); int n,m,i,j,k,x,y,q,z; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d%d",&zb[i][0],&zb[i][1]); scanf("%d",&m); memset(dis,0x7f,sizeof(dis));//清為最大值,以便後面求最短路 for(i=1;i<=m;i++){ scanf("%d%d",&x,&y); dis[x][y]=sqrt(pow(1.0*(zb[x][0]-zb[y][0]),2)+pow(1.0*(zb[x][1]-zb[y][1]),2));//計算兩點之間的距離 dis[y][x]=dis[x][y]; } scanf("%d%d",&q,&z); }</span>
最後輸出結果:<span style="font-size:18px;">for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i!=j&&j!=k&&i!=k) dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);</span>
<span style="font-size:18px;">printf("%.2f",dis[q][z]);</span>
2、Dijkstra演算法O(n²)
還是先進行初始化:<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double f[105][105];//用f[x][y]來存x,y的距離(但不是最短距離)
double dis[105];//存最終結果
bool b[105];//判斷重複
int zb[105][2];
int main()
{
//freopen("dijkstra.in","r",stdin);
//freopen("dijkstra.out","w",stdout);
int n,m,i,j,k,x,y,q,z,xi;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d%d",&zb[i][0],&zb[i][1]);
scanf("%d",&m);
memset(f,0x7f,sizeof(f));
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
f[x][y]=sqrt(pow(1.0*(zb[x][0]-zb[y][0]),2)+pow(1.0*(zb[x][1]-zb[y][1]),2));
f[y][x]=f[x][y];
}
scanf("%d%d",&q,&z);
}</span>
我們可以發現dis變成了一維陣列,因為Dijkstra演算法是一種用來計算一個點到其他所有點的最短路徑演算法,
Dijkstra演算法是先用一個迴圈變數 i 來列舉所有點,把每一個列舉過的點在b陣列中標記為1,然後記錄下距離
點 i 最近的一個點 k ,以點 k 來進行其他最短距離的更新,
<span style="font-size:18px;">for(i=1;i<=n;i++)
dis[i]=f[q][i];
b[q]=1;
dis[q]=0;
for(i=1;i<=n-1;i++){
xi=10000000;
k=0;
for(j=1;j<=n;j++){
if(b[j]==0&&dis[j]<xi){
xi=dis[j];
k=j;
}
}
if(k==0)
break;
b[k]=1;
for(j=1;j<=n;j++)//進行更新
dis[j]=min(dis[j],dis[k]+f[k][j]);
}
printf("%.2f",dis[z]);</span>