道路升級(最小生成樹KRUSKAL)
阿新 • • 發佈:2018-12-19
道路升級
問題描述
Z國有 n 個城市和 m 條雙向道路,每條道路連線了兩個不同的城市,保證所有城市之間都可以通過這些道路互達。每條道路都有一個載重量限制,這限制了通過這條道路的貨車最大的載重量。道路的編號從 1 至 m 。巧合的是,所有道路的載重量限制恰好都與其編號相同。
現在,要挑選出若干條道路,將它們升級成高速公路,並滿足如下要求:
- 所有城市之間都可以通過高速公路互達。
- 對於任意兩個城市 u,v 和足夠聰明的貨車司機:只經過高速公路從 u 到達 v 能夠裝載貨物的最大重量,與經過任意道路從 u 到達 v 能夠裝載貨物的最大重量相等。(足夠聰明的司機只關注載重量,並不在意繞路)
在上面的前提下,要求選出的道路數目儘可能少。
求需要挑選出哪些道路升級成高速公路(如果有多種方案請任意輸出一種)。
輸入
第一行 2 個用空格隔開的整數 n,m ,分別表示城市數目、道路數目。
第 2 行到第 m+1 行,每行 2 個用空格隔開的整數 u,v 描述一條從 u 到 v 的雙向道路,第 i+1 行的道路的編號為 i 。
注意:資料只保證不存在連線的城市相同的道路(自環),並不保證不存在兩條完全相同的邊(重邊)
輸出
第一行一個整數 k ,表示升級成高速公路的道路數。
接下來 k 行每行一個整數,從小到大輸出所有選出的道路的編號。
輸入樣例
3 3
1 2
2 3
1 3
輸出樣例
2
2
3
資料範圍
對於 20% 的資料,保證 n≤5,m≤10。
對於 60% 的資料,保證 n≤1,000,m≤5,000。
對於 100% 的資料,保證 n≤200,000,m≤400,000。
時間限制:10 sec
空間限制:256 MB
提示
[提示1:真的可能有多種方案嗎?]
[提示2:k 是否一定為 n-1 呢?(也就是說,選出的道路是否恰好構成了一棵樹?)]
[提示3:這道題和最小生成樹有什麼關係呢?]
#include <bits/stdc++.h> using namespace std; const int N = 500005; //並查集 class UnionSet{ public: int f[N]; //初始化父節點 n:節點數量 開始每個節點的父節點是它自己本身 void init(int n){ for(int i=1; i<=n; i++) f[i] = i; } //查詢節點x所在集合的根(路徑壓縮) //x:節點x //返回值:根 int find(int x){ return f[x] == x?x:f[x]=find(f[x]); } //將x節點與y節點所在集合合併 //x:一個節點 //y:一個節點 //返回值:返回true表示成功合併,返回false表示已經在一個集合裡了 bool merge(int x,int y){ int setX = find(x); int setY = find(y); if(setX != setY){ f[setX] = setY; return true; } return false; } }us; // 給定一個n個點m條邊的無向圖,第i條邊邊權為i,求所有需要升級的邊 // n:n個點 // m:m條邊 // U:大小為m的陣列,表示m條邊的其中一個端點 // V:大小為m的陣列,表示m條邊的另一個端點 // 返回值:所有需要升級的邊,從小到大排列;第一小問的答案自然即為返回值的size,所以你不必考慮如何返回size vector<int> getAnswer(int n, int m, vector<int> U, vector<int> V) { vector<int> ans; us.init(n); //構造最大生成樹,找權值最大的邊 for(int i=m-1; i>=0; --i) if(us.merge(U[i],V[i])) ans.push_back(i+1);//加入邊,從1開始的 reverse(ans.begin(),ans.end()); return ans; } int main() { int n, m; scanf("%d%d", &n, &m); vector<int> U, V; for (int i = 0; i < m; ++i) { int u, v; scanf("%d%d", &u, &v); U.push_back(u); V.push_back(v); } vector<int> ans = getAnswer(n, m, U, V); printf("%d\n", int(ans.size())); for (int i = 0; i < int(ans.size()); ++i) printf("%d\n", ans[i]); return 0; }