天天看點

【模闆】最短路徑之Dijkstra算法

是一種貪心的單源最短路徑算法(可證明)。

注意點:

1. 圖的鍊式存儲(vector數組方式)。

2. 循環n次。可分為兩大步驟:加入新的節點後更新最短距離、尋找下一個節點(要有最短距離)并加入集合。

時間複雜度:

【模闆】最短路徑之Dijkstra算法
//Dijstra算法
#include<cstdio>
#include<vector>
using namespace std;
struct E{
	int next;	//代表直接相鄰的頂點
	int c;		//代表該邊的權值 
}; 
vector<E> edge[2001];	//鄰接連結清單
bool mark[2001];		//标注為True時表示該結點最短路徑長度得到,已加入集合K
int Dis[2001];	//當标注為True時是已得的最短路徑長度,
				//否則是從1出發,經過已知的最短路徑達到K中的某節點,再經過一條邊到達i結點的路徑中的最短距離
int main(void)
{
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)		//路口數、道路數 
	{
		//if(n==0&&m==0) break;
		for(int i=1;i<=n;i++) edge[i].clear();	//初始化鄰接連結清單
		while(m--)
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			E tmp;
			tmp.c = c;
			tmp.next = a;
			edge[b].push_back(tmp);		//将鄰接資訊加入鄰接連結清單 
			tmp.next = b;
			edge[a].push_back(tmp);		//再次加入,因為是無向圖 
		 } 
		for(int i=1;i<=n;i++)//因為結點從1開始 
		{
			Dis[i]=-1;		//所有結點不可達 
			mark[i]=false; 		//是以結點不屬于K 
		}
		Dis[1]=0;	//得到最近的結點為1,長度是0 
		mark[1]=true; 	//将結點1加入K
		int newP = 1;	//集合K新加入的結點是1
		for(int k=1;k<n;k++)	//循環n-1次,按照最短路徑遞增确定其它n-1個結點的最短路徑長度
		{
			for(int j=0;j<edge[newP].size();j++)	//周遊新加入結點的直接相鄰的邊
			{
				int t = edge[newP][j].next;		//直接相鄰的邊的另一端 
				int c = edge[newP][j].c;		//直接相鄰的邊的權重 
				if(mark[t]==true) continue;	//另一端結點如果已經在集合K了,跳過
				if(Dis[t]==-1||Dis[t]>Dis[newP]+c)	//如果該結點尚不可達,或者該結點t從新加入的結點NewP經過該邊到達的路徑更短
				{
					Dis[t] = Dis[newP]+c;	//更新最短距離資訊 
				 } 
			} 
			int min =123123123;//初始化大整數
			for(int j=1;j<=n;j++)	//周遊所有的結點 
			{
				if(mark[j]==true) continue; 	//結點屬于K則跳過
				if(Dis[j]==-1)	continue;		//若該結點仍然不可達,也跳過
				if(Dis[j]<min)	//若該結點經由結點至集合K中的某點在經過一條邊到達的距離小于目前最小值 
				{
					min = Dis[j];		//更新其為最小值 
					newP = j;		//新加入的結點暫定為這個點 
				 } 
			 } 
			 mark[newP] = true;		//确定為新加入結點 
		 }  
		 printf("%d\n",Dis[n]);
	}
	return 0;
 } 
           

 2019/04/14 第一次錯誤更正:程式錯誤(更新的是新加入結點鄰接邊的另一端結點)。