HDU 1232 畅通工程
并查集系列题目:http://acm.hdu.edu.cn/problemclass.php?id=721
畅通工程
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 20380 Accepted Submission(s): 10543
Problem Description
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最少还需要建设的道路数目。
Sample Input
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
Sample Output
1 0 2 998
Hint Huge input, scanf is recommended.
自己写的代码:
#include<stdlib.h> #include<stdio.h> #include<string.h> #define maxn 1001 int id[maxn]; void init(){ int i; for(i=0;i<maxn;i++) id[i]=-1; } int find_root(int x){ if(id[x]==-1) return x; else id[x]=find_root(id[x]); return id[x]; } void Union(int x,int y){ int rx=find_root(x); int ry=find_root(y); if(rx==ry) return; id[ry]=rx; } int main(){ int n,m,a,b,sum,i; while(scanf("%d",&n)!=EOF && n!=0){ scanf("%d",&m); init(); while(m--){ scanf("%d %d",&a,&b); Union(a,b); } sum=0; for(i=1;i<=n;i++) sum+=(id[i]==-1); printf("%d\n",sum-1); } }
另一个版本:
#include<stdlib.h> #include<stdio.h> #include<string.h> #define maxn 1001 int id[maxn]; int rank[maxn]; void init(){ int i; for(i=0;i<maxn;i++){ id[i]=-1; rank[i]=1; } } int find_root(int x){ if(id[x]==-1) return x; else id[x]=find_root(id[x]); return id[x]; } void Union(int x,int y){ int rx=find_root(x); int ry=find_root(y); if(rx==ry) return; if(rank[rx]>rank[ry]){ id[ry]=rx; rank[rx]+=rank[ry]; } else{ id[rx]=ry; rank[ry]+=rank[rx]; } } int main(){ int n,m,a,b,sum,i; while(scanf("%d",&n)!=EOF && n!=0){ scanf("%d",&m); init(); while(m--){ scanf("%d %d",&a,&b); Union(a,b); } sum=0; for(i=1;i<=n;i++) sum+=(id[i]==-1); printf("%d\n",sum-1); } }
结果见下图:
他人模板:
1: //并查集+路径压缩+加权优化树
2: #include<iostream>
3: using namespace std;
4: const int maxn = 1001;
5: int parent[maxn];
6: void Make_set(){
7: for(int i=0;i<maxn;i++)
8: parent[i]=-1;
9: }
10: int Find(int x){ //查找+非递归的路径压缩
11: int s=x;
12: while(parent[s]>0) s=parent[s];
13: while(x!=s){ //路径压缩
14: int temp=parent[x];
15: parent[x]=s;
16: x=temp;
17: }
18: return x;
19: }
20: void Union(int R1, int R2){
21: int r1=Find(R1), r2=Find(R2);
22: if(r1==r2) return;
23: int temp=parent[r1]+parent[r2];
24: //parent[r1]<0 && parent[r2]<0
25: if(parent[r1]>parent[r2]){
26: parent[r1]=r2;
27: parent[r2]=temp;
28: }
29: else{
30: parent[r2]=r1;
31: parent[r1]=temp;
32: }
33: }
34: int main(){
35: //freopen("in.txt","r",stdin);
36: for(int n,m,a,b;cin>>n&& n!=0;){
37: Make_set();
38: cin>>m;
39: while(m--){
40: cin>>a>>b;
41: Union(a,b);
42: }
43: int num=0;
44: for(int i=1;i<=n;i++)
45: if(parent[i]<0) num++;
46: cout<<num-1<<'\n';
47: }
48: }
吉林大学版:
1: //Abstract: UFSet
2: //Author:Lifeng Wang (Fandywang)
3: // Model One 与Model 2 路径压缩方式不同,合并标准不同
4: const int MAXSIZE = 500010;
5: int rank[MAXSIZE]; // 节点高度的上界
6: int parent[MAXSIZE]; // 根节点
7: int FindSet(int x){// 查找+递归的路径压缩
8: if( x != parent[x] ) parent[x] = FindSet(parent[x]);
9: return parent[x];
10: }
11: void Union(int root1, int root2){
12: int x = FindSet(root1), y = FindSet(root2);
13: if( x == y ) return ;
14: if( rank[x] > rank[y] ) parent[y] = x;
15: else{
16: parent[x] = y;
17: if( rank[x] == rank[y] ) ++rank[y];
18: }
19: }
20: void Initi(void){
21: memset(rank, 0, sizeof(rank));
22: for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
23: }
24: //Model Two
25: const int MAXSIZE = 30001;
26: int pre[MAXSIZE]; //根节点i,pre[i] = -num,其中num是该树的节点数目;
27: //非根节点j,pre[j] = k,其中k是j的父节点
28: int Find(int x){//查找+非递归的路径压缩
29: int p = x;
30: while( pre[p] > 0 ) p = pre[p];
31: while( x != p ){
32: int temp = pre[x]; pre[x] = p; x = temp;
33: }
34: return x;
35: }
36: void Union(int r1, int r2){
37: int a = Find(r1); int b = Find(r2);
38: if( a == b ) return ;
39: //加权规则合并
40: if( pre[a] < pre[b] ){
41: pre[a] += pre[b]; pre[b] = a;
42: }
43: else {
44: pre[b] += pre[a]; pre[a] = b;
45: }
46: }
47: void Initi(void)
48: {
49: for( int i=0; i < MAXSIZE; ++i ) pre[i] = -1;
50: }