杭电畅通工程
问题描述:n个城镇,任何两个城镇可以互通,还需要多少条路?
思路:就是查找连通分量的个数,标记每一个结点的前导点,判断是否根节点是否一致。有x个连通分量,那么就需要至少x-1条边
输入:n个城市 m条边
通过并查集的思想可以很有效的求出连通分量的个数。以下有一个点非常重要,p1 = find(a);p2 = find(b);如果二者的root不同,那么现在给定的a-b的连线,就需要将这俩的root标记成相同的。如果每一次都用p(a) = p(b),
测试一下:可以发现,每一次的前导点会覆盖掉之前的,形不成并查集。
3 3
2 1
2 3
3 1
1 3 1
正确写法是:par[p1] = p2;
/*
杭电畅通工程
问题描述:n个城镇,任何两个城镇可以互通,还需要多少条路?
思路:就是查找连通分量的个数,标记每一个结点的前导点,判断是否根节点是否一致。有x个连通分量,那么就需要至少x-1条边
输入:n个城市 m条边
*/
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
const int MAX_N = 1000;
int par[MAX_N];
int find(int root){
int son = root;
while(par[root] != root){
root = par[root];
}
while(son!=root){
int tmp = par[son];
par[son] = root;
son = tmp;
}
return root;
}
int main(){
int n, m,a,b; // n个城市,m条路 ,a---b
set<int> s;
while(cin>>n && n){
int total = n - 1;
for(int i = 1; i <= n; i++) par[i] = i; // 全部初始化为自己
cin>>m;
while(m--){
cin>>a>>b;
int p1,p2;
p1 = find(a);
p2 = find(b);
if (p1 != p2){ // 说明还没有联通
par[p1] = p2;
total -= 1;
}
}
for(int i = 1; i <= n; i++) cout<<par[i]<<" ";
cout<<endl<<"还需要"<<total<<endl;
}
return 0;
}
输入:
10 9
7 8
9 1
8 1
6 2
3 2
5 10
10 4
4 5
3 6
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
第一个例子的输出前导点序列:1 2 2 4 4 2 8 1 1 4