D69 最短路 拓扑+Dijkstra 算法 P3008 [USACO11JAN] Roads and Planes G
D69 最短路 拓扑+Dijkstra 算法 P3008 [USACO11JAN] Roads and Planes G_哔哩哔哩_bilibili
P3008 [USACO11JAN] Roads and Planes G - 洛谷
思路
这道题求从源点到各点的最短路。题中给出的图有无向边和单向边,其中单向边边权可能为负,这就告诉我们不能直接用 Dijkstra,用 SPFA 可能被卡。
注意到无向边边权是非负的,这提示我们可以在无向边上跑 Dijkstra。如果将无向边连接的点缩为一点,这个图就是一个DAG,DAG 可以用拓扑求最短路。
所以我们就分开考虑,首先求出若干个由无向边组成的连通块,对于块内的点,通过 Dijkstra 更新最短路;然后在块与块之间,用拓扑排序一层一层地进行更新;最后就可以求出源点 s 到各点的最短路了。

相关板子:
D02【模板】最短路 Dijkstra 算法 P4779 单源最短路径 - 董晓 - 博客园
// 最短路 拓扑+Dijkstra 算法 O(mlogn) #include<bits/stdc++.h> #define inf 0x3f3f3f3f #define pii pair<int,int> using namespace std; const int N=25005; int n,r,p,s; vector<pii> e[N]; int bel[N],cnt,rd[N],vis[N],d[N]; vector<int> block[N]; void dfs(int u){ bel[u]=cnt; block[cnt].push_back(u); for(auto [v,w]:e[u]) if(!bel[v]) dfs(v); } void work(){ memset(d,0x7f,sizeof d);//0x7f>0x3f d[s]=0; queue<int> q;//队列 priority_queue<pii,vector<pii>,greater<pii> > pq;//小根堆 q.push(bel[s]);//s块入队 for(int i=1;i<=cnt;i++) if(!rd[i]) q.push(i);//入度为0的块入队 while(!q.empty()){ //块外拓扑 int b=q.front();q.pop(); for(int u:block[b]) pq.push({d[u],u});//块内点入堆 while(!pq.empty()){ //块内Dijkstra int u=pq.top().second;pq.pop(); if(vis[u]) continue; vis[u]=1; for(auto [v,w]:e[u]){ if(d[v]>d[u]+w){ d[v]=d[u]+w; if(bel[v]==bel[u]) pq.push({d[v],v});//点入堆 } if(bel[v]!=bel[u]&&(--rd[bel[v]])==0) q.push(bel[v]);//块入队 } } } } int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>r>>p>>s;//城镇的数量,道路的数量,航线的数量,中心城镇 for(int i=1,a,b,c;i<=r;i++){ //双向边 cin>>a>>b>>c; e[a].push_back({b,c}); e[b].push_back({a,c}); } for(int i=1;i<=n;i++)if(!bel[i]) ++cnt,dfs(i);//缩点 for(int i=1,a,b,c;i<=p;i++){ //单向边 cin>>a>>b>>c; e[a].push_back({b,c}); rd[bel[b]]++;//块的入度 } work();//拓扑+Dijkstra for(int i=1;i<=n;i++) if(d[i]>inf) cout<<"NO PATH"<<'\n'; else cout<<d[i]<<'\n'; }
// 双端队列优化SPFA算法 // 距离小于队头则从队头入队,否则从队尾入队 #include<bits/stdc++.h> using namespace std; const int N=25010; int n,r,p,s,a,b,c; vector<pair<int,int>> e[N]; int d[N],inq[N]; void spfa(int s){ memset(d,0x3f,sizeof d); d[s]=0; deque<int> q; q.push_back(s); inq[s]=1; while(q.size()){ int u=q.front(); q.pop_front(); inq[u]=0; for(auto [v,w]:e[u]){ if(d[v]>d[u]+w){ d[v]=d[u]+w; if(!inq[v]){ if(q.size()&&d[v]<d[q.front()]) q.push_front(v); else q.push_back(v); inq[v]=1; } } } } } int main(){ ios::sync_with_stdio(0); cin>>n>>r>>p>>s; for(int i=1; i<=r; i++){ cin>>a>>b>>c; e[a].push_back({b,c}); e[b].push_back({a,c}); } for(int i=1; i<=p; i++){ cin>>a>>b>>c; e[a].push_back({b,c}); } spfa(s); for(int i=1; i<=n; i++) if(d[i]==0x3f3f3f3f) cout<<"NO PATH"<<"\n"; else cout<<d[i]<<"\n"; }
浙公网安备 33010602011771号