道路升级
问题描述
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 n,int m,vector<int> A,vector<int> B){
//一开始父节点都是自己
//连通的道路为0
for(int i = 1;i <= n;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;
if(r[setA] == r[setB])
r[setA]++;
}
else F[setB] = setA;
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(n,m,A,B);
//输出升级到高速公路的的数目
cout << JL.size() << "\n";
//输出每条升级到高速公路的编号
while(!JL.empty()){
cout << JL.back() << "\n";
JL.pop_back();
}
return 0;
}
训练营讲解做法转载:https://blog.csdn.net/zhaohaibo_/article/details/81455832