算法提高课-图论-单源最短路的综合应用-AcWing 342. 道路与航线:最短路dijkstra、拓扑排序 、综合题、好题
生活随笔
收集整理的這篇文章主要介紹了
算法提高课-图论-单源最短路的综合应用-AcWing 342. 道路与航线:最短路dijkstra、拓扑排序 、综合题、好题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目分析
來源:acwing
分析:
道路:雙向,邊權非負,
航線:單向,邊權可正可負,且無環。
根據題意,點可以分為很多團(連通塊),團內部只有道路(道路是雙向的,而且是連通的,所以不能存在航線,否則有環,矛盾);而航線是在團與團之間。航向滿足什么呢? 團與團之間的航線也是無環的,是滿足拓撲序的。所以,團與團之間是有向無環圖。
本題:
思路是:先把每個團看成1個點,用拓撲序掃描來處理;然后對于每個團,內部使用dijkstra算。
id[]:存儲每個點屬于哪個連通塊;
vector< int> block[]:存儲每個連通塊里有哪些點
如果id[ver] == id[j],如果j能被更新,則把j插入到堆中;
如果id[ver] != id[j],則將id[j] 這個連通塊的入度-1,如果減到0,則將其插入到拓撲排序的隊列中。
ac代碼
#include<bits/stdc++.h> #define x first #define y second using namespace std; typedef pair<int,int> PII; const int N = 25010, M = 150010; const int INF = 0x3f3f3f3f; int n, mr, mp, S; int h[N],e[M],w[M],ne[M],idx; int id[N]; //每個點屬于哪個連通塊 vector<int> block[N]; // 每個連通塊中有哪些點 int bcnt; // 連通塊的個數 int dist[N]; bool st[N]; int din[N];// 每個連通塊的入度queue<int> q;void add(int a, int b, int c){e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++; }// 把連通的點放到連通塊中 void dfs(int u, int bid){id[u] = bid; // u這點放到bid這個block中block[bid].push_back(u);// 遍歷連通的所有臨邊for(int i = h[u]; ~i; i = ne[i]){int j = e[i];if(!id[j]) dfs(j, bid); // 都放到bid這個連通塊中}}// 求每個連通塊內部的最短路 void dijkstra(int bid){priority_queue<PII, vector<PII>, greater<PII>> heap;for(auto ver : block[bid]) heap.push({dist[ver],ver});while(heap.size()){auto t = heap.top();heap.pop();int ver = t.y, distance = t.x;if(st[ver]) continue;st[ver] = true;for(int i = h[ver]; ~i; i = ne[i]){int j = e[i];if(dist[j] > dist[ver] + w[i]){dist[j] = dist[ver] + w[i];if(id[j] == id[ver]) heap.push({dist[j], j});}if(id[j] != id[ver] && -- din[id[j]] == 0)q.push(id[j]);}} }void topsort(){memset(dist, 0x3f, sizeof dist);dist[S] = 0;for(int i = 1; i <= bcnt; i ++){if(!din[i])q.push(i); // 把入度為零的連通塊加入隊列中}while(q.size()){int t = q.front();q.pop();dijkstra(t); //對編號為t的連通塊進行dijkstra}}int main(){cin >> n >> mr >> mp >> S;memset(h, -1, sizeof h);while(mr --){int a, b, c;scanf("%d%d%d", &a, &b, &c);add(a, b, c), add(b, a, c);}// 所有的點分類到不同的連通塊// 放在id[]數組中for(int i = 1; i <= n; i ++){if(!id[i])dfs(i, ++ bcnt); }// 讀入航線while(mp --){int a, b, c;scanf("%d%d%d",&a, &b, &c);add(a, b, c);din[id[b]] ++; // 后者所在連通塊的入度+1}topsort();for(int i = 1; i <= n; i ++)if(dist[i] > INF/ 2) puts("NO PATH");else printf("%d\n", dist[i]); }題目來源
https://www.acwing.com/problem/content/344/
總結
以上是生活随笔為你收集整理的算法提高课-图论-单源最短路的综合应用-AcWing 342. 道路与航线:最短路dijkstra、拓扑排序 、综合题、好题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法提高课-图论-单源最短路的综合应用-
- 下一篇: 算法提高课-数学知识-矩阵乘法-AcWi