鄧俊輝 演算法訓練營練習 道路升級
阿新 • • 發佈:2018-12-14
道路升級 問題描述 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
#include <bits/stdC++.h> using namespace std; const int N = 500005; //F[N] 用來記錄父節點 //r[N] 用來記錄此集合的元素個數(即:連通道路的數目) int F[N]; int r[N]; //查詢最上面的父節點 int find(int x){ return F[x] == x?x:find(F[x]); } // JL用來記錄升級道路的編號 vector<int> JL; void getAnswer(int m,vector<int> A,vector<int> B){ //一開始父節點都是自己 //連通的道路為0 for(int i = 0;i < m;i++){ F[i] = i; r[i] = 0; } //從載重量大的道路開始連通 for(int i = m - 1;i >= 0;i--){ //尋找A[i] 與 B[i] 的父節點 int setA = find(A[i]); int setB = find(B[i]); //如果父節點不同說明兩個城市還沒有接通 if(setA != setB) //此時尋找 道路數多的 一方的父親節點作為 父親節點 if(r[setA] >= r[setB]){ F[setB] = setA; r[setA] += r[setB];//道路數相加 JL.push_back(i + 1);//記錄升級了第幾條道路 } } } int main(int argc, char const *argv[]) { //n個城市 m條道路 int n,m; scanf("%d%d",&n,&m); //A[i] - B[i]代表 兩條連通的通路 vector<int> A; vector<int> B; for(int i = 0;i < m;i++){ int ai,bi; scanf("%d%d",&ai,&bi); A.push_back(ai); B.push_back(bi); } getAnswer(m,A,B); //輸出升級到高速公路的的數目 cout << JL.size() << "\n"; //輸出每條升級到高速公路的編號 while(!JL.empty()){ cout << JL.back() << "\n"; JL.pop_back(); } return 0; }