1. 程式人生 > >迪傑斯特拉(Dijkstra)演算法--無向網路最短路徑

迪傑斯特拉(Dijkstra)演算法--無向網路最短路徑

與有向網路不同的是,無向網路的鄰接矩陣是對稱的,所以在構造鄰接矩陣的時候要注意。Dijkstra演算法的具體內容參照我上次寫的迪傑斯特拉(Dijstra)演算法——有向網路最短路徑

下面直接放程式碼和例項,以便更加理解使用。

#include<stdio.h>
#define max 1000                        //1000定義為最大值正無窮,表示兩點之間不直接相通,或與自己相連線。
#define n 100                           //n表示一個範圍,需要大於圖的頂點數目,以便定義一個數組儲存。n的具體值根據情況而定。
main()
{
	void DIJ(float C[n][n],int v);
	int i,j,k,e,r;
	float z;
	float a[n][n];                       //定義一個足夠大的陣列,用於儲存圖的資料。
	for(i=0;i<n;i++)
	for(j=0;j<n;j++)
	{
		a[i][j]=max;                      //在正式寫入資料之前,定義任意兩點之間是不連通的,以便在後面為連通的資料單獨賦值。
	}
	printf("請輸入頂點數目和邊數:");      //明確圖中的節點數目和之間的邊數。
	scanf("%d%d",&r,&e);
	printf("輸入各邊關係和權值:\n");
	for(k=0;k<e;k++)                      //輸入各邊之間的連線點與權值。如1,2點之間的距離是10,應該輸入“1 2 10”。
	{
		scanf("%d%d%f",&i,&j,&z);
		a[i-1][j-1]=z;                    //只建立有向圖用這句
		a[j-1][i-1]=z;                  //建立無向圖時需要加上這行
	}
	printf("\n構造鄰接矩陣:");
	for(i=0;i<r;i++)                       //把圖用鄰接矩陣的形式輸出。
	{
		printf("\n");
		for(j=0;j<r;j++)
		{
			printf("%.1f\t",a[i][j]);
		}
	}
	printf("\n");
	printf("請輸入起始點數字:");           //輸入需要從某個節點開始。
	scanf("%d",&i);
	printf("\n距離\t路徑");
	DIJ(a,i);
}
void DIJ(float C[n][n],int v)                //Dijkstra演算法
{
	float D[n];                              //用於儲存起始點到其他各點間的距離
	int P[n],S[n];                           //P[n]用陣列儲存當前點的前驅結點,S[n]表示已經取過的點集,代表紅點集。
	int i,j,k,v1,pre;
	float min,inf=200;                       //inf一定要大於所有點間路徑最大的數,這樣才保證距離最大值的點能擴充到已經取好的點
	v1=v-1;
	for(i=0;i<n;i++)                        
	{
		D[i]=C[v1][i];                       //置初始距離值
		if(D[i]!=max)                        //初始狀態下各前驅結點。
			P[i]=v;
		else P[i]=0;                         //如果兩點非連線定義其前驅為0
	}
	for(i=0;i<n;i++)                          
		S[i]=0;                              //紅點集開始是空集
	S[v1]=1;                                 //初始點入紅點集
	D[v1]=0;                                 //設定初始點到自身的距離為0
	for(i=0;i<n-1;i++)                       //擴充紅點集
	{
		min=inf;                              
		for(j=0;j<n;j++)                     
			if((!S[j])&&(D[j]<min))
			{
				min=D[j];
				k=j;
			}
			S[k]=1;							//在當前藍點集中選取距離最小的頂點k+1,並加入紅點集
			for(j=0;j<n;j++)
				if((!S[j])&&(D[j]>D[k]+C[k][j]))//調整各藍點的間距值
				{
					D[j]=D[k]+C[k][j];         //修改藍點j+1到紅點集的距離
					P[j]=k+1;                  //改變j+1的前驅為k+1
				}
	}										//所有頂點都擴充到S中
	for(i=0;i<n;i++)
	{
		if(D[i]!=max)
		printf("\n%.1f\t%d",D[i],i+1);        //列印兩點間能連通的結果
		pre=P[i];
		while(pre!=0)							//用於繼續找前驅結點
		{
			printf("<--%d",pre);
			pre=P[pre-1];
		}
	}
	printf("\n");
}

有向網路和無向網路程式碼只有一行之差別,但是實際輸出結果卻大不相同。 下面以具體例項驗證。 有向網路圖 在這裡插入圖片描述 把上面的有向網路圖改成無向網路圖 在這裡插入圖片描述 鄰接矩陣也發生變化 在這裡插入圖片描述 以4為源點,輸出結果對比如下 有向網路輸出結果: 有向網路輸出結果 無向網路輸出結果: 在這裡插入圖片描述 由以上可以看出兩次輸出結果截然不同。

下面以另一個例子作為驗證。

下面是一個無向網路 在這裡插入圖片描述 鄰接矩陣在這裡就不再給出。 以4為源點,輸出結果如下 在這裡插入圖片描述 如果按照上圖輸入,就可以得到上圖結果。