1. 程式人生 > >問題 1708: 演算法7-15:迪傑斯特拉最短路徑演算法

問題 1708: 演算法7-15:迪傑斯特拉最短路徑演算法

題目描述

在帶權有向圖G中,給定一個源點v,求從v到G中的其餘各頂點的最短路徑問題,叫做單源點的最短路徑問題。

在常用的單源點最短路徑演算法中,迪傑斯特拉演算法是最為常用的一種,是一種按照路徑長度遞增的次序產生最短路徑的演算法。

可將迪傑斯特拉演算法描述如下:

在本題中,讀入一個有向圖的帶權鄰接矩陣(即陣列表示),建立有向圖並按照以上描述中的演算法求出源點至每一個其它頂點的最短路徑長度。

輸入

輸入的第一行包含2個正整數n和s,表示圖中共有n個頂點,且源點為s。其中n不超過50,s小於n。

以後的n行中每行有n個用空格隔開的整數。對於第i行的第j個整數,如果大於0,則表示第i個頂點有指向第j個頂點的有向邊,且權值為對應的整數值;如果這個整數為0,則表示沒有i指向j的有向邊。當i和j相等的時候,保證對應的整數為0。

輸出

只有一行,共有n-1個整數,表示源點至其它每一個頂點的最短路徑長度。如果不存在從源點至相應頂點的路徑,輸出-1。

請注意行尾輸出換行。

樣例輸入

4 1
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

樣例輸出

6 4 7 

提示

在本題中,需要按照題目描述中的演算法完成迪傑斯特拉演算法,並在計算最短路徑的過程中將每個頂點是否可達記錄下來,直到求出每個可達頂點的最短路徑之後,演算法才能夠結束。

迪傑斯特拉演算法的特點是按照路徑長度遞增的順序,依次新增下一條長度最短的邊,從而不斷構造出相應頂點的最短路徑。

另外需要注意的是,在本題中為了更方便的表示頂點間的不可達狀態,可以使用一個十分大的值作為標記。

 

來源

資料結構高分筆記

 

#include<stdio.h>
#define N 120
int e[N][N],dis[N],book[N],i,j,n,m,t1,t2,t3,u,v,min;
int intf;
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		intf=9999999;
//		for(i=1;i<=n;i++)
//			for(j=1;j<=n;j++)
//				if(i==j)
//					e[i][j]=0;
//				else
//				{
//					e[i][j]=intf;
//					e[j][i]=intf;
//				}
					
		for(i=0;i<n;i++)
			for(j=0;j<n;j++)
			{
				scanf("%d",&e[i][j]);
				if(e[i][j]==0&&i!=j)
					e[i][j]=intf;
			}
		for(i=0;i<n;i++)
			dis[i]=e[m][i];
			
		for(i=0;i<n;i++)
			book[i]=0;
		book[m]=1;
		
		for(i=0;i<n-1;i++)
		{
			min=intf;
			for(j=0;j<n;j++)
			{
				if(book[j]==0&&dis[j]<min)
				{
					min=dis[j];
					u=j;
				}
			}
			book[u]=1;
			for(v=0;v<n;v++)
			{
				if(e[u][v]<intf)
				{
					if(dis[v]>dis[u]+e[u][v])
						dis[v]=dis[u]+e[u][v];
				}
			}
		}
		for(i=0;i<n;i++)
		{
			if(i!=m&&dis[i]!=intf)
				printf("%d ",dis[i]);
			if(dis[i]==intf)
				printf("-1 ");
		}
		printf("\n");
	}
	return 0;
}