dijkstra堆優化

再求單源最短路徑時,算法有優劣之分,個人認爲在時間方面 樸素dijkstra>bellmanford>SPFA>dijkstra+heap,所以掌握dijkstra堆優化對於OIER是必要的。

本文主要解說迪傑斯特拉堆優化的板子以及它所用到的知識;dijkstra算法、快讀、stl以及鏈式前向星請自行百度或者看我的其他文章。

代碼如下,註釋個人覺得已經很清楚了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int cnt=0;//邊的序號 
int dis[5000010],vis[5000010],h[5000010];//dis:起點到該點的長度   vis:是否訪問過了   h:起點爲h[?]的暫存平臺 
struct node//next:下一個連接某個點的下一條邊   to:該邊指向的下一條邊   val:邊權 
{
	int next,to,val;
	//int from; from在鏈式前向星的遍歷裏意義不大 
}edg[5000010];
struct heapnode//重載小根堆
{
	int num,dist;//num:標號   dist:距離 
	bool operator<(heapnode t) const//記住這種特殊寫法就可以了 
	{
		return dist>t.dist;//與sort相反,此處爲從小到大 
	}
};
priority_queue<heapnode>q;//定義一個heapnode形式的優先隊列q 
int cread()//快讀 
{
	int f=1,x=0;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
void add(int u,int v,int val)
{
	++cnt;//一條新邊 
	edg[cnt].to=v;//記錄到哪裏 
	edg[cnt].val=val;//記錄邊權 
	edg[cnt].next=h[u];//鏈式前向星的菊花搜圖法 
	h[u]=cnt;//暫存桌面 
}
int main()
{
	int n,m,s;//n:點數   m:邊數   s:起點 
	n=cread();m=cread();s=cread();
	int x,y,z;
	for(int i=1;i<=m;i++)
	{
		x=cread();y=cread();z=cread();
		add(x,y,z);
	}
	for(int i=1;i<=n;i++)dis[i]=0x7fffffff;//初始化極大值需要用for,memset會出錯 
	memset(vis,0,sizeof(vis));//初始化訪問標記 
	dis[s]=0;//起點到起點自然爲0 
	heapnode tem;//定義一個跑腿tem 
	tem.dist=0;tem.num=s;//記錄起點信息 
	q.push(tem);//跑腿記錄的東西入隊 
	while(!q.empty())//隊不空 
	{
		heapnode u=q.top();//使用u記錄隊首信息(最小值) 
		q.pop();//隊首gg 
		if(vis[u.num])continue;//假如已經訪問過了,跳過 
		vis[u.num]=1;//標記訪問過了 
		for(int i=h[u.num];i!=0;i=edg[i].next)//鏈式前向星式菊花搜圖 
		{
			int v=edg[i].to;//記錄某條邊的到達處 
			if(!vis[v]&&(dis[v]>dis[u.num]+edg[i].val))//假如說v沒被訪問過並且原來到v的路程大於從這條邊經過的到v路程 
			{
				dis[v]=dis[u.num]+edg[i].val;//更新到v的路程 
				tem.num=v;tem.dist=dis[v];//跑腿記錄v的信息 
				q.push(tem);//跑腿入隊 
			}
		}
	}
	for(int i=1;i<=n;i++) printf("%d ",dis[i]);//到每個點的距離輸出 
	return 0;
}

 

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