1. 程式人生 > >鄰接表實現dijkstra演算法

鄰接表實現dijkstra演算法

先放程式碼:

#include <bits/stdc++.h>
using namespace std;
#define edgeN 5000005
#define pointN 1000005
#define infinity 2147483647
int pointnum,edgenum,startpoint,cnt(0),dis[pointN],vis[pointN],head[pointN];
struct node{
	int distance_to_presentpoint,present_point;
	inline bool operator <(const node &x) const{
		return distance_to_presentpoint > x.present_point;	
	}
};
priority_queue<node>q;
//we usually use "pair< , >" here,why we use struct is to help us to understand the processes.
struct Edge{
	int from,to,dis,next;
	//"to" is the end spot of the edge.
	//"next" is the edge after the present one.
}edge[edgeN];
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9') if(ch=='-')f=-1,ch=getchar();
	while(ch>='0'&&ch<'9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
inline void add_edge(int from,int to,int dis){
	edge[++cnt].from=from;//record the start spot of this edge.
	edge[cnt].to=to;//record the end spot of this edge.
	edge[cnt].dis=dis;//record the length of this edge.
	edge[cnt].next=head[from];//record the next edge of this one.
	head[from]=cnt;//put this edge into the head array.
}
inline void dijkstra(){
	for(int i=1;i<=pointnum;i++) dis[i]=infinity;
	dis[startpoint]=0;
	/*super important*/q.push((node){0,startpoint});
	while(!q.empty()){
		//save the top of the heap(the shortest edge in the heap)and pop it off
		node temp=q.top();
		q.pop();
		int nowposition=temp.present_point;
		//if it hasn't been visited, visit it
		if(vis[nowposition]==1) continue;
		vis[nowposition]=1;
		for(int i=head[nowposition];i;i=edge[i].next){
			//search for all the edge of the top of the heap
			int nextpoint=edge[i].to;
			if(dis[nextpoint]>dis[nowposition]+edge[i].dis){
				dis[nextpoint]=dis[nowposition]+edge[i].dis;
				q.push((node){dis[nextpoint],nextpoint});//push the next point into the queue 
			}
		}
	}
}
int main(){
	pointnum=read();edgenum=read();startpoint=read();
	for(int i=1,frompoint,topoint,distance;i<=edgenum;i++){
		frompoint=read();topoint=read();distance=read();
		add_edge(frompoint,topoint,distance);
	}
	dijkstra();
	for(int i=1;i<=pointnum;i++){
		if(dis[i]!=infinity) printf("to point %d the shortest distance is %d\n",i,dis[i]);
		printf("there is no way to point %d\n",i);
	}
	return 0;
}

  1. 這是一種稍有缺陷的求單元最短路問題的常用演算法,它可以求得每一個點到起點間的(當然肯定得是有通路的點)最小距離。

  2. 它的主要思想是從起點開始,對每一個點的出邊進行比較,然後選擇出邊邊權值最小的目標點入隊並開始下一輪擴充套件。核心思想:貪心演算法

  3. 其主要的缺陷是如果遇到兩點間邊權為負值時會出錯(這一點Bellman-Ford可以完美解決),這一點需要注意。

  4. 其時間複雜度為O(n^2),通過優先佇列(priority_queue)的優化後可以達到O(mlongn)。

  5. 上面的模板就是使用了堆優化的模板。並使用了鄰接表儲存,能更方便地處理資料較大的時候的空間問題,如果要用鄰接矩陣儲存,則部分程式碼如下:

	//令鄰接矩陣名為f,即:f[][];
	//需要用到的陣列有:bool vis[]/*標記點有沒有走到過(入隊過)*/;int dis[]/*記錄每個點到起點的距離,在最開始時,除了直接與起點相連的以外,其他點的dis都為極大值*/;
	//需要有的變數有:minn/*記錄最小值*/,inf/*這個應該為const int,即定義的最大值,一般為0x3f3f3f3f*/,position/*當前在哪個點*/;
	int Dijkstra(int start_point){
		//初始化;
		memset(vis,false,sizeof(vis);
		for(int i=1;i<=點的總數;i++){
			dis[i]=inf;
		} 

		vis[start]=true;dis[start]=0;/*起點到自己的距離為0*/;
		for(int i=1;i<=點的總數;i++){//初始化起點及與其相連的點;
			dis[i]=f[start][i];
		}
		for(int i=1;i<=點的總數-1;i++){//由於起點為已知,故所需要遍歷的點的個數為總數減一;
			minn=inf;
			for(int j=1;j<=點的總數;j++){//選擇入隊哪一個與這個點相連的點;
				if(!vis[j]&&minn>dis[j]){
					minn=dis[j];
					position=j;
				}
			}
			vis[position]=true;//將擴充套件的點標記為已經走過;
			for(int j=1;j<=點的總數;j++){//由於新擴展出了點,更新dis[]的值;
				if(!vis[j])	dis[j]=min(dis[j],dis[position]+f[position][j]);
			}
		}
		return dis[n];
	}

文章原創,請勿抄襲