日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法提高课-图论-单源最短路的综合应用-AcWing 342. 道路与航线:最短路dijkstra、拓扑排序 、综合题、好题

發布時間:2025/4/5 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法提高课-图论-单源最短路的综合应用-AcWing 342. 道路与航线:最短路dijkstra、拓扑排序 、综合题、好题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目分析


來源:acwing

分析:
道路:雙向,邊權非負,
航線:單向,邊權可正可負,且無環。

根據題意,點可以分為很多團(連通塊),團內部只有道路(道路是雙向的,而且是連通的,所以不能存在航線,否則有環,矛盾);而航線是在團與團之間。航向滿足什么呢? 團與團之間的航線也是無環的,是滿足拓撲序的。所以,團與團之間是有向無環圖。

本題:

  • 如果邊權非負,可以用dijkstra算法。時間復雜度是O(mlogn)
  • 如果是拓撲圖,不管邊權是正是負,均可按拓撲序掃描,時間復雜度是線性的。
  • 思路是:先把每個團看成1個點,用拓撲序掃描來處理;然后對于每個團,內部使用dijkstra算。

  • 先讀入所有雙向道路,然后dfs所有連通塊,計算兩個數組:
    id[]:存儲每個點屬于哪個連通塊;
    vector< int> block[]:存儲每個連通塊里有哪些點
  • 輸入所有航線,同時統計出每個連通塊的入度。
  • 按照拓撲序依次處理每個連通塊。先將所有入度為0的連通塊的編號加入隊列。
  • 每次從隊頭取出一個連通塊的編號bid
  • 將該block[bid]中的所有點加入堆中,然后對堆中的所有點跑dijkstra算法。
  • 每次取出堆中距離最小的點ver。
  • 然后遍歷所有與ver相鄰的點j。
    如果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、拓扑排序 、综合题、好题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。