再求單源最短路徑時,算法有優劣之分,個人認爲在時間方面 樸素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;
}