Hdu 2473 Junk-Mail Filter (并查集的删除)

本文探讨了使用并查集解决集合合并与分解的问题,包括实现细节与具体实例解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:有n个集合,m个操作。对每个操作输入的如果为M,那就合并两个集合,否则将此点分离出去,问一共有多少个集合。

举例:对于

M 0 2
M 1 2
S  2

合并后的集合是{0,1,2},把2删除掉之后, 集合变为 {0,1}

思路:建立一个映射,通过改变将删除点的映射关系,同时改变其父节点到一个新的、虚设的点。这种方法很费空间。

直接将一个点的父节点改成自身是不行的,因为如果这点已经是一个集合的根节点,那它的父节点本来就等于自身。

#include <cstdio>
#include <cstring>

const int N=1100005;

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

	void Init (int n)
	{//本题对应元素为0~n-1
		for (int i=0;i<n;i++)
			Make_Set (i);
        id=n;        //////
	}

	void Make_Set (int x)
	{
		father[x]=x;
		mapping[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];
		}
	}

	void Delete (int x)
	{//改变待删除点的映射数组
	    father[id]=id;
	    mapping[x]=id++;
    }
}ob;

bool visit[N];

int main ()
{
	int n,m,Cas=1;
	while (scanf("%d%d",&n,&m),n||m)
	{
		ob.Init(n);
		char str[4];
		int a,b;
		while (m--)
        {
            scanf("%s%d",str,&a);
            if (str[0]=='M')
            {
                scanf("%d",&b);  //利用映射值
                ob.Union(ob.mapping[a],ob.mapping[b]);
            }
            else
                ob.Delete(a);
        }
        memset(visit,false,sizeof(visit));
        int ans=0;
        for (int i=0;i<n;i++)
        {
            a=ob.Find_Set(ob.mapping[i]);
            if (visit[a]==false)
            {
                ans++;
                visit[a]=true;
            }
        }
        printf("Case #%d: %d\n",Cas++,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值