并查集 Hdu 1272 (判环)+ Hdu 1213 + Hdu 1232 + Hdu 3172

Hdu 1272 小希的迷宫

思路:两点的根节点相同,并且他们又彼此连通,则说明构成环。如果无环且 点数-1==边数 则说明只有一个连通块

#include <cstdio>
#include <cstring>

const int MAX=100005;

bool visit[MAX];

class Disjoint_Set
{
public:
	int father[MAX];            /*father[x]表示x的父节点*/
	int rank[MAX];              //以该节点为根节点的点数,同时起到按秩合并的作用

	void Init (int n)
	{
		for (int i=0;i<=n;i++)
			Make_Set (i);
	}

	void Make_Set (int x)
	{
		father[x]=x;
		rank[x]=1;
	}

	int Find_Set (int x)
	{
		if (x != father[x])
			father[x] = Find_Set(father[x]);//回溯
		return father[x];
	}

	bool Union (int x,int y)
	{//返回false表示要合并的两点已在同一个集合中
		int a=Find_Set (x);
		int b=Find_Set (y);
		if (a == b)
			return false;
		if (rank[a] >= rank[b])
		{
			father[b]=a;
			rank[a]+=rank[b];
		}
		else
		{
			father[a]=b;
			rank[b]+=rank[a];
		}
		return true;
	}
}ob;

int main ()
{
	int n,m;
	while (~scanf("%d%d",&n,&m),n!=-1 && m!=-1)
    {
        if (n==0 && m==0)
        {
            printf("Yes\n");
            continue;
        }
		ob.Init(MAX);
		memset(visit,false,sizeof(visit));
		visit[n]=visit[m]=true;
		ob.Union(n,m);
		int cnt=1;   //已经有一条边
		int tmp=2;   //已经有2个点
		bool flag=true;
		while(scanf("%d%d",&n,&m),n||m)
        {
            cnt++;
            if (visit[n]==false)
            {
                visit[n]=true;
                tmp++;
            }
            if (visit[m]==false)
            {
                visit[m]=true;
                tmp++;
            }
            if (ob.Union(n,m)==false)
                flag=false;  //若n和m的根节点相同,并且他们又彼此连通,则说明构成环
        }
		if (flag && cnt==tmp-1) //无环,且所有点连通
            printf("Yes\n");
        else
            printf("No\n");
	}
	return 0;
}

Hdu 1213 How Many Tables

题意:有n个人参加的party,要准备多少张桌子,使得任意桌子上坐的人都是相互认识的。求最少要准备的桌子的数量。

#include <cstdio>

const int MAX=1005;

class Disjoint_Set
{
public:
	int father[MAX];            /*father[x]表示x的父节点*/
	int rank[MAX];              //以该节点为根节点的点数,同时起到按秩合并的作用

	void Init (int n)
	{
		for (int i=0;i<=n;i++)
			Make_Set (i);
	}

	void Make_Set (int x)
	{
		father[x]=x;
		rank[x]=1;
	}

	int Find_Set (int x)
	{
		if (x != father[x])
			father[x] = Find_Set(father[x]);//回溯
		return father[x];
	}

	void Union (int x,int y)
	{
		int a=Find_Set (x);
		int b=Find_Set (y);
		if (a == b)
			return;
		if (rank[a] >= rank[b])
		{
			father[b]=a;
			rank[a]+=rank[b];
		}
		else
		{
			father[a]=b;
			rank[b]+=rank[a];
		}
	}
}ob;

int main ()
{
	int T,n,m;
	scanf("%d",&T);
	while (T--)
    {
        scanf("%d%d",&n,&m);
		ob.Init(n);
		int a,b,ans=0,i;
		for (i=1;i<=m;i++)
		{
			scanf("%d%d",&a,&b);
            ob.Union(a,b);
		}
		for (i=1;i<=n;i++)
            if (ob.father[i]==i)
                ans++;
		printf("%d\n",ans);
	}
	return 0;
}

Hdu 1232 畅通工程

#include <cstdio>

const int MAX=1005;

class Disjoint_Set
{
public:
	int father[MAX];
	int rank[MAX];              //以该节点为根节点的点数,同时起到按秩合并的作用

	void Init (int n)
	{
		for (int i=0;i<=n;i++)
			Make_Set (i);
	}

	void Make_Set (int x)
	{
		father[x]=x;
		rank[x]=1;
	}

	int Find_Set (int x)
	{
		if (x != father[x])
			father[x] = Find_Set(father[x]);//回溯
		return father[x];
	}

	void Union (int x,int y)
	{
		int a=Find_Set (x);
		int b=Find_Set (y);
		if (a == b)
			return;
		if (rank[a] >= rank[b])
		{
			father[b]=a;
			rank[a]+=rank[b];
		}
		else
		{
			father[a]=b;
			rank[b]+=rank[a];
		}
	}
}ob;

int main ()
{
	int n,m;
	while (~scanf("%d%d",&n,&m),n)
       {
		ob.Init(n);
		int a,b,ans=0,i;
		for (i=1;i<=m;i++)
		{
			scanf("%d%d",&a,&b);
            ob.Union(a,b);
		}
		for (i=1;i<=n;i++)
            if (ob.father[i]==i)
                ans++;
		printf("%d\n",ans-1);
	}
	return 0;
}

Hdu 3172 Virtual Friends

给出m条交友信息,每一句含两个人名,表示两个人成为朋友,求是这两个人朋友的有多少个人(含自己)

时间卡的比较严,名字不要用STL的string,用map映射时间还是可以接受的

输入格式很坑爹

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

const int MAX=100005;

class Disjoint_Set
{
public:
	int father[MAX];            /*father[x]表示x的父节点*/
	int rank[MAX];              //以该节点为根节点的点数,同时起到按秩合并的作用

	void Init (int n)
	{
		for (int i=0;i<=n;i++)
			Make_Set (i);
	}

	void Make_Set (int x)
	{
		father[x]=x;
		rank[x]=1;
	}

	int Find_Set (int x)
	{
		if (x != father[x])
			father[x] = Find_Set(father[x]);//回溯
		return father[x];
	}

	void Union (int x,int y)
	{
		int a=Find_Set (x);
		int b=Find_Set (y);
		if (a == b)
			return;
		if (rank[a] >= rank[b])
		{
			father[b]=a;
			rank[a]+=rank[b];
		}
		else
		{
			father[a]=b;
			rank[b]+=rank[a];
		}
	}
}ob;

int main ()
{
	int T,n;
	while (~scanf("%d",&T))
	while (T--)
    {
        scanf("%d",&n);
		ob.Init(MAX);
		int id=1;
		char str[25],ch[25];
		map<string,int> m;
		for (int i=1;i<=n;i++)
		{
			scanf("%s%s",str,ch);
			if (m[str]==0)
                m[str]=id++;
            if (m[ch]==0)
                m[ch]=id++;
            int a=m[str];
            int b=m[ch];
            ob.Union(a,b);
            printf("%d\n",ob.rank[ ob.Find_Set(m[str]) ]);
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值