【HDU 2473】Junk-Mail Filter

【题目】

题目传送门Junk-Mail Filter

Description

我简略地说一下题目意思吧

有多组数据,每组数据有 n 个物品,m 个操作,你要支持以下两种操作:

1、M X Y,将 X 和 Y 合并(放入同一个集合中)
2、S X,将 X 从原来的集合中删除,放入一个新的集合中

求出经过 m 次操作之后还有多少个集合

Sample Input

5 6
M 0 1
M 1 2
M 1 3
S 1
M 1 2
S 3

3 1
M 1 2

0 0

Sample Output

Case #1: 3
Case #2: 2

【分析】

这道题的话,操作 M 很好做,用并查集就行了,但是删除不太好做,听说并查集中删点的代码要写300多行

一个简单的做法是对于每个要删除的点 x,新建一个节点 y,然后将 x 指向 y,以后要用 x 的时候用 y 就可以了

emmm……是不是很简单,接下来看代码吧

【代码】

注意这些物品是从 0 开始编号的

sum[ i ] 记录的是 i 号集合中物品的个数

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000005
using namespace std;
int id[N],sum[N],father[N];
int find(int x)
{
    if(father[x]!=x)
      father[x]=find(father[x]);
    return father[x];
}
void merge(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y) return;
    father[y]=x;
    sum[x]+=sum[y];
    sum[y]=0;
}
int main()
{
    int n,m,i,x,y,ans,num=0;
    char c;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
    	if(!n&&!m)
    	  break;
    	ans=0;
    	num++;
        for(i=0;i<=n+m;++i)
        {
        	id[i]=i;
        	sum[i]=1;
        	father[i]=i;
        }
        for(i=1;i<=m;++i)
        {
            c=getchar();
            c=getchar(); 
            if(c=='M')
            {
            	scanf("%d%d",&x,&y);
                merge(id[x],id[y]);
            }
            if(c=='S')
            {
                scanf("%d",&x);
                sum[find(id[x])]--;
                id[x]=n++;
            }
        }
        for(i=0;i<n;i++)
          if(sum[i])
            ans++;
        printf("Case #%d: %d\n",num,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81302005