hdu 2473并查集+节点映射

来源:互联网 发布:mac迅雷下载失败提示 编辑:程序博客网 时间:2024/05/22 03:51

这道题是到好题,要想做出这道题,得学会节点映射。。

因为题目中讲了,有合并,还有删除, 那删除一个节点后,其他的节点关系依旧,但是这个被删除的节点就得孤立, 而且被孤立之后可能重新回到某个集合中,那如何处理呢?

就是映射,比如1到n ,,,,,,现在要合并的是4 和  5 号节点,我们合并的并不是  4  和  5 ,而是 Union(mp[4],mp[5]),mp[i]就是节点i 的映射。。

最后判断有多少个不同特征的邮件就 看有少个结合,也就是看有多少个点事根节点。。

请看代码:

#include <iostream>
#define N 1001000
using namespace std;
int f[N],mp[N],cnt[N];   //这块数组得开这么大,不然wrong 尽管题目要求的是 10 的5次方,
int find(int x)//查
{
  if(f[x]!=x)
        f[x]=find(f[x]);
  return f[x];
}
void make(int a,int b)//并
{
  int f1=find(a);
  int f2=find(b);
  if(f1!=f2)
  {
     f[f1]=f2;
     cnt[f2]+=cnt[f1];
     cnt[f1]=0;        //因为该点的父节点转移了,所以让他的cnt[]置0,为了后面的根节点个数的判断。。
  }
}
int main()
{
 int n,m,test=0;
 while(scanf("%d%d",&n,&m)!=EOF)
 {
    if(n==0&&m==0)break;
    test++;
    for(int i=0;i<n;i++)
    {
       f[i]=i;
       mp[i]=i; //初始化时,每个节点的映射先等于本身
       cnt[i]=1;
    }
    char s[10];
    int a,b;
    for(int i=0;i<m;i++)
    {
      //getchar();
      scanf("%s",s);
      if(s[0]=='M')
      {
         scanf("%d%d",&a,&b);
         make(mp[a],mp[b]); 
      }
      else if(s[0]=='S')
      {
         scanf("%d",&a);
         int root=find(mp[a]);  //映射操作,每次并的,查的不是这个编号本身,而是这个编号的映射
         cnt[root]--;
         mp[a]=n++;
         f[mp[a]]=mp[a];
         cnt[mp[a]]=1; 
      }
    }
    int sum=0;
    for(int i=0;i<n;i++)
        if(cnt[i])sum++;
    printf("Case #%d: %d\n",test,sum);
 }
 return 0;
}

0 0
原创粉丝点击