天天看點

c++ Dijkstra堆優化(Set)

因為蒟蒻太弱了,是以搞個普及組最短路卡了兩天,寫個随筆聊以紀念。

Dijkstra,圖論最短路算法基礎算法之一,也是從時間複雜度上來說較優的算法(不卡負權的情況下)。

正常樸素算法O(N^2),起碼比隔壁Floyed強。。。

本着精益求精的精神,神犇們創造出了一種名為堆優化的東東。

有人可能問,SPFA不香嗎?

關于SPFA,它死了。。。

1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<set>
 6 #include<cstring>
 7 using namespace std;
 8 const int MAXN=1e5+5,MAXM=2e5+5;
 9 int n,m,s,cnt;
10 int head[MAXM],dis[MAXN];
11 bool vis[MAXN];
12 struct edge{
13     int to,dist,next; //to:指向的後續節點  dist:邊權    next:類指針操作
14     //不會的可以康康鍊式前向星講解 
15 }e[MAXM];
16 void addedge(int u,int v,int w){
17     e[cnt].to=v;
18     e[cnt].dist=w;
19     e[cnt].next=head[u];
20     head[u]=cnt++; //存圖 
21 }
22 typedef pair<int,int> PII; //偷懶。。。
23 //pair中,first=dis(邊權),second=pos (後續節點下标)
24 set<PII> heap; //建立一個set容器,其内部預設以first升序排列 
25 void Dijkstra(){
26     heap.insert(make_pair(0,s)); //存入初始節點 
27     dis[s]=0;
28     while(!heap.empty()){ //若容器為空,則說明無點可周遊 
29         PII tmp=*heap.begin(); //取最小邊進行更新 
30         heap.erase(heap.begin()); //删掉已經用過的最小邊 
31         int x=tmp.second; //下标 
32         vis[x]=1; //标記用過 
33         for(int i=head[x]; i!=-1; i=e[i].next){
34             int y=e[i].to; //以x為起點,挨個周遊連結清單中的後續節點 
35             if(!vis[y] && dis[x]+e[i].dist<dis[y]){ //沒走過,且可以更新 
36                 heap.erase(make_pair(dis[y],y)); //删掉原先不是最優的點 
37                 dis[y]=dis[x]+e[i].dist;
38                 heap.insert(make_pair(dis[y],y)); //加入已更優的點 
39                 // 先将對應的 pair 從堆中删除,再将更新後的 pair 插入堆
40             }
41         }
42     }
43 }
44 int main(){
45     ios::sync_with_stdio(false);
46     memset(head,-1,sizeof(head)); //初始化 
47     memset(dis,0x7f,sizeof(dis));
48     cin>>n>>m>>s;
49     for(int i=1; i<=m; i++){
50         int u,v,w;
51         cin>>u>>v>>w;
52         addedge(u,v,w);
53     }
54     Dijkstra();
55     for(int i=1; i<=n; i++) cout<<dis[i]<<" ";
56     return 0;
57 }