并查集

并查集:是数据结构里面比较简单的一种~~

稍微看看,你应该就会懂,现在我来总结一下,

并查集,是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。

如果忘了,可以看自己的收集的资料~~不多讲述.


入门题:

hdu  1232 1272 1274 1213  1856

现在详细讲解一下,省的到时候忘记了~~

hdu 1232 入门题

#include <iostream>
#include <cstdio>
using namespace std;

int pow[1001];
int sum;

int find(int r)  //查找
{
  int i=r,j;	
  while(pow[r]!=r) 
   r=pow[r];
   
 /*
 while(i!=r) //路径压缩 
  {
  	j=pow[i];
    pow[i]=r;
	i=j;	
  }  */
  return r; 
}

void unions(int x,int y)  //  合并
{
  int a=find(x);
  int b=find(y);
  
  if(a!=b){        
      pow[a]=b;
	  sum--;  	
   }
}

int main()
{
  int n,m;
  int x,y;
  while(cin>>n,n)
  {
  	cin>>m;
    sum=n-1;
    
    for(int i=1;i<=n;i++)
      pow[i]=i;	
   
   for(int i=0;i<m;i++){
   	// cin>>x>>y;
	 scanf("%d%d",&x,&y);
	 unions(x,y);
   } 	                  	     
   
    cout<<sum<<endl;
  }	
	return 0;
}

hdu  1272


#include <iostream>
using namespace std;

int pow[100001];
bool vis[1001][1001];
int sum(0);
int finds(int r)
{
   while(r!=pow[r])
     r=pow[r];
   return r;	 	
}

void unions(int x,int y)
{
   int a=finds(x);
   int b=finds(y);
   if(a!=b)
     pow[a]=b;	
} 

int main()
{
 int x,y;
 int max(0);
 memset(vis,0,sizeof(vis));
 
 for(;;)
 {
   cin>>x>>y;
   if(x==y==-1) break; 	
   
   if(x==y==0){
   	    sum=max-1;
   	  
   	  for(int i=1;i<=max;i++)
   	    pow[i]=i;
    for(int i=1;i<=max;i++)
	  for(int j=1;j<=max;j++)
	   if(vis[i][j]){
   		   unions(i,j);
   		   sum--;
   	     } 	
   	 cout<<sum<<endl;
     max=0;
	 memset(vis,0,sizeof(vis));		   
   	
  }
   
    vis[x][y]=1;    
     if(max<x) max=x;  if(max<y) max=y; 
  
 }  	
	return 0;
}



hdu 1213


#include <iostream>
using namespace std;

int pow[1001];
int sum;

int find(int r)
{
  while(r!=pow[r])
   r=pow[r];
   return r;
}

void unions(int x,int y)
{
  int a=find(x);
  int b=find(y);
  
   if(a!=b){
  	pow[a]=b;
  	sum--;
  } 	
}

int main()
{
  int t;
  int m,n;
  
  cin>>t;
  while(t--)
  {
  	int x,y;   
	cin>>n>>m;
  	sum=n;
  	
  	for(int i=1;i<=n;i++)
  	 pow[i]=i;
  	 
	for(int i=0;i<m;i++)
	 {
       cin>>x>>y;
	   unions(x,y);		
 	 }
	cout<<sum<<endl;	
  }	
	return 0;
}



hdu 1274


#include <iostream>
using namespace std;

const int size=100000;
int low[100001];
bool vis[100001];

int find(int r)
{
   while(r!=low[r])
    r=low[r];
  return r;	
}

bool unions(int x,int y)
{
  int a=find(x);
  int b=find(y);
  if(a==b) return 0;
  else {
  	 low[a]=b;
  	 return 1;
  }   	
}
int main()
{
  int a,b;
  int max(0),sum(0);
  while(cin>>a>>b,a!=-1&&b!=-1)
  {
  	if(a==0&&b==0){
	  	cout<<"Yes"<<endl;
	  	continue;
	  }
  	
    bool f=1;
    max=a>b?a:b;

  	for(int i=1;i<=size;i++) 
	   low[i]=i;
    memset(vis,0,sizeof(vis));
    vis[a]=vis[b]=1;
    
    if(unions(a,b))
     while(cin>>a>>b,a+b){
     	if(!unions(a,b))
     	 f=0;
     	 vis[a]=vis[b]=1;
     	if(max<a) max=a;
		if(max<b) max=b; 
     }
     
   sum=0;  	  	
   for(int i=1;i<=max;i++)
      if(low[i]==i&&vis[i])sum++;
	  
	   
    if(f&&sum==1)cout<<"Yes"<<endl; 
     else cout<<"No"<<endl; 		
  	 
  }	
	return 0;
}


hdu 1856

这一题得吐槽一下哭,这个输入0的时候得输出1,还有数据比较大得优化~~ 

优化方法有两种迭代和循环~~

这题wa了好多次~~一个小错误害死我了 

  int a[4],我取了个i=4悲剧了


#include <iostream>
using namespace std;
const int size=10000001;

int pow[size];
int cus[size];
int findsum;

int find(int r)
{
  int i=r,j;
  
  if(r!=pow[r]) //迭代优化 
    pow[r]=find(pow[r]);
    return pow[r];
   
 /*
while(r!=pow[r])  // 循环优化(优化也就是路径压缩) 
   r=pow[r];  
    
 while(i!=r)
  {
  	j=pow[i];
  	pow[i]=r;
  	i=j;
  }   
 	 
  return r;*/
}

void unions(int x,int y)
{
  int a=find(x);
  int b=find(y);
 
  if(a!=b){
  	  pow[a]=b;
	  cus[b]+=cus[a]; 
	  if(cus[b]>findsum)
	   findsum=cus[b];
  }	
}

int main()
{
	int t;
	while(cin>>t)
	{
	  int x,y;
      findsum=1;  	  
	  for(int i=1;i<size;i++){
   		pow[i]=i; cus[i]=1;
   	  } 
	  
      for(int i=0;i<t;i++)
	   {
   	     cin>>x>>y;
		 unions(x,y); 		
   	   }	
    
      cout<<findsum<<endl; 	   
	}
	return 0;
}

还有一种做法,一开始就应该ac的可惜 i=size i取了等号 大哭,找了好久没发现,然后看了别人ac的代码,写了第一种方法~~


#include <iostream>
using namespace std;
const int size=10000001;

int pow[size];
int cus[size];

int find(int r)
{
  int i=r,j;
  while(r!=pow[r])
    r=pow[r];
             
  while(i!=r)
  {
    j=pow[i];
    pow[i]=r;
    i=j;    
  }
  
  return r;
}

void unions(int x,int y)
{
  int a=find(x);
  int b=find(y);
 
  if(a!=b){
        pow[a]=b;
      cus[b]+=cus[a]; // cus[a]=0; 有没有无关紧要
  }    
}

int main()
{
    int t;
    while(cin>>t)
    {
      int x,y;
      int sum(0),findsum(1);
      
      for(int i=1;i<size;i++){
           pow[i]=i; cus[i]=1;
         } 
      
      for(int i=0;i<t;i++)
       {
            cin>>x>>y;
         if(sum<x) sum=x;
         if(sum<y) sum=y;
         
         unions(x,y);         
          }    
          
         for(int i=1;i<=sum;i++)
       if(findsum<cus[i]) findsum=cus[i];
    
      cout<<findsum<<endl;        
    }
    return 0;
}

好了现在哦了,看完了 并查集,该看其他的算法了~~









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值