圖論-Dijkstra

      Dijkstra-迪傑斯特拉 算法 算法是處理單源最短路徑問題常用的算法,雖然時間複雜度(n^2)較高(但是可以優化),但是編寫起來方便在處理小數據時還是很方便的.

      dijkstra 算法,在使用時需要指定一個起始點 n,因爲這是 計算一個點到其它點最短路徑的算法,這裏需要 3 個數組 S , U 和flag 來輔助完成,其中 S 數組用來儲存 點 i 到 n 的 最短路徑 即 S[i] ,U 數組來儲存 還未 計算最短路徑的 點 ,flag[i] 說明 點 i 已經 被計算出到n的最短路徑 ,來看看過程是怎樣的

      假如 有 4 個 點 A B C D 計算 A到其餘三點的最短路徑(如下圖)

  ① 開始 S中只有A本身 ,U 中爲剩餘節點 S {A(0)} U {B(3),C(5),D(max)}

A(0) 表示 A 到 其本身的距離 爲 0 ,D(max) 表示 D與A在一開始沒有直接連接

  ② 現在 U中尋找距離A點最近的點 (這個點到A肯定是最短的了) 我們找到了B,所以 將 B加入S中 並在U中去除(用flag標記一下就OK)

這時 數組是 S{A(0),B(3) } U{C(3),D(MAX)} 然後我們再拿剛拿出的點B能直接到達的點 :只有C 我們看到 AB + BC < AC 然後將 U 中的 C(5) 換成 C (4);

   ③ 重複 ① ② 操作;

簡單介紹了過程之後看一下如何用代碼實現(我代碼將S 和 U合併了):

#include<stdio.h>
#include<string.h>
#define MAXN 10000000
int maps[100][100];
int s[100];//用來存儲點到原點的距離 假設 點由數字 1-100 表示 
int flag[100];//用來判斷點是否計算過
void init(){  
	int i,j;
	memset(flag,-1,sizeof(int)*100);
	for (i=0;i<100;i++)
	for (j=0;j<100;j++)
	{
		if (i==j)
		maps[i][j] = 0;
		else
		maps[i][j] = MAXN;
	}

} 
void dijkstra(int x,int n){ //X 表示 起始點 ,n表示點的數量 
	int i,j,k;
	for (i=1;i<=n;i++)
	s[i] = maps[x][i];
	s[x] = 0;
	flag[x] = 1;
	for (i=1;i<=n;i++)
	{
		int min = MAXN;
		for (j=1;j<=n;j++)
		{
			if (flag[j]==-1 && min > s[j])
			{
				min = s[j]; //記錄最小值 
				k = j; // 記錄最小值的點 
			}
		}
		flag[k] = 1;//標記最小值的點 該點距離起始點已是最短距離
		for (j=1;j<=n;j++)
		{
			if (flag[j]!=1&&s[k]+maps[k][j] < s[j])
			{
				s[j] = min + maps[k][j];
			}
		 } 
	}
}
int main (){
	int i,n,m,a,b,c,x;//n表示點的個數 m表示邊的個數,a,b 存儲點 ,c存儲邊的權值,x爲起始點 
	scanf("%d%d",&n,&m);
	init();
	for (i=0;i<m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		maps[a][b] = c;
		maps[b][a] = c;
	}
	scanf("%d",&x);
	dijkstra(x,n);
	for (i=1;i<=n;i++)
	printf("%d\n",s[i]);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章