并查集的简单例题(HDU - 1213,POJ - 2524,POJ - 1611)

并查集的简单例题(基础)
HDU - 1213
题意:每次给两个人,找出最后的帮派数(帮派之间没有共同的一个人,否则将是一个帮派了)
思路:①最简单的并查集应用,直接套用模板。
②利用DFS进行搜索也可以。

代码:
并查集:

#include<iostream>
#include<cstdlib> 
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int p[M],v[M];
int is(int a)
{
    int g=a,h=a;
    while(g!=p[g])
    {
        g=p[g];
    }
    while(h!=g)//状态压缩,否则最后的遍历可能要超时。
    {
        int k=p[h];
        p[h]=g;
        h=k;
    }
    return g;
}
int main()
{
    int tt,i,j,m,n,x,y,ans;
    cin>>tt;
    while(tt--)
    {
        ans=0;
        me(v,0);
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            p[i]=i;
        }
        for(i=0;i<m;i++)
        {
            cin>>x>>y;
            int l=is(x),r=is(y);
            if(l!=r)
            {
              if(l>r)swap(l,r);
              p[r]=l;
            }
        }
        for(i=1;i<=n;i++)
        {
            v[is(i)]=1;
        }
        for(i=1;i<=n;i++)
        {
            if(v[i]!=0)ans++;
        }
        cout<<ans<<endl;
    }
    //system("pause");
    return 0;
}

DFS做法:(我本来也不知道可以这样做,后来看网上可以这样写)

#include<iostream>
#include<cstdlib> 
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int ans,n;
int v[M],q[1100][1100];
void dfs(int u)
{
    int i;
    v[u]=1;
    for(i=1;i<=n;i++)
    {
        if(!v[i])
        {
            if(q[i][u])
            {
                dfs(i);
                
            }
        }
    }
    
    
}
int main()
{
    int tt,i,j,m,x,y;
    cin>>tt;
    while(tt--)
    {
        ans=0;
        me(q,0);
        me(v,0);
        cin>>n>>m;
        for(i=1;i<=m;i++)
        {
            cin>>x>>y;
            q[x][y]=1;
            q[y][x]=1;
        }
        for(i=1;i<=n;i++)
        {
      //从0~n查找v[i]等于0的人,等于0说明他还没有所属帮派,所以帮派加1 
            if(!v[i])
            {
                  dfs(i);
                  ans++;
            }
            
        }
        cout<<ans<<endl;
    }
    //system("pause");
    return 0;
}

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

POJ - 2524
题意:与上题一样,求帮派数。
思路:并查集,代码与上题基本一样。
代码:

#include<iostream>
#include<cstdlib> 
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int v[M],p[M];
int is(int root)
{
    int g=root;
    while(p[g]!=g)
    g=p[g];
    while(root!=g)
    {
        int k=p[root];
        p[root]=g;
        root=k;
    }
    return g;
}
void Qi(int l,int r)
{
    int s=is(l);
    int s1=is(r);
    if(s1==s)return ;
    p[s]=s1; 
}
int main()
{
    int i,x,y,n,tt=0;
    LL m;
    while(cin>>n>>m)
    {
        if(!n&&!m)break;
        int ans=0;
        me(v,0);
        for(i=1;i<=n;i++)
        {
            p[i]=i;
        }
        for(i=1;i<=m;i++)
        {
            cin>>x>>y;
            if(x<y)swap(x,y);//这里我取比较小的,也可以不选,结果一样。
            Qi(x,y);
        }
        for(i=1;i<=n;i++)
        {
            v[is(i)]=1;
        }
        for(i=1;i<=n;i++)
        {
            if(v[i])ans++;
        }
        printf("Case %d: %d\n",++tt,ans);
    }
    //system("pause");
    return 0;
}

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

POJ - 1611
题意:给出几个帮派,帮派之间可能有相互认识的人,所以这两个(多个)帮派有可以合并。找到与0号在一个帮派的所以人(包括0号)。

思路:在输入每个帮派时,将其中某一个定为老大(我习惯与把最小号定为老大)在把老大能连接的帮派给连上,在让这个输入的帮派其他人的父节点等于这个老大。

代码:

#include<iostream>
#include<cstdlib> 
#include<sstream>
#include<cstdio>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
#define me(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
const int N = 1000005;
const int M = 500005;
int p[M],a[M];
int is(int root)
{
	if(root==p[root])
	return p[root];
	else return p[root]=is(p[root]);
}
int main()
{
	int n,m,i,j,k,minn;
	while(cin>>n>>m)
	{
		if(!n&&!m)break;
		for(i=0;i<n;i++)
		p[i]=i;
		int ans=0;
       for(i=0;i<m;i++)
	   {
		   cin>>k;
		   minn=inf;
		   for(j=1;j<=k;j++)
		   {
			   scanf("%d",&a[j]);
			   minn=min(a[j],minn);
		   }
		   p[is(minn)]=minn;
		   p[minn]=minn;	
		   for(j=1;j<=k;j++)
		   {
			   if(a[j]!=minn)
			   {
				   p[is(a[j])]=minn;
			   }
		   }
	   }
	   int x=is(0);
	   for(i=1;i<n;i++)
	   {
		   if(is(i)==x)ans++;
	   }
	   cout<<ans+1<<endl;
	}
	//system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值