1. 程式人生 > >圖論演算法----最短路徑Floyed演算法和Dijkstra演算法詳解

圖論演算法----最短路徑Floyed演算法和Dijkstra演算法詳解

一、題目描述

最短路徑問題(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³) 我們先對輸入的資料進行初始化:
<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>
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;">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>