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); 
	} 
}

结果见下图:

hdu1232

他人模板:

   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:  } 
posted @ 2013-04-05 00:59  姜楠  阅读(169)  评论(0编辑  收藏  举报