HDU ACM 2473 Junk-Mail Filter (并查集)

 

http://acm.hdu.edu.cn/showproblem.php?pid=2473

 题意:输入 M 数字1 数字2 表示数字1和数字2是同一个集合.

     S 数字1 表示数字1需要从集合中删除.求有几个集合

 

用并查集实现.

普通的并查集并不能实现删除的功能.

所以需要使用 "代理".

为了好理解先用两个数组.

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

未进行删除前.

进行删除后

删除节点并不是真的删除这个节点,而是把要删除的节点更换为另一个节点.

以后搜索他也是搜索另一个节点.

这样不会破坏并查集的结构又实现了删除.

 

在查找几个集合时要用used数组标记而不是判断 father[i] == i

若1为根节点,而1又被删除时则会出现错误.

View Code
  1 #include <iostream>
  2 #include <string>
  3 using namespace std;
  4 
  5 const int MAX = 100000 + 10;
  6 int father[MAX*100];
  7 int rank1[MAX*100];
  8 int sign[MAX*100];
  9 
 10 void Make_Set(int x)//初始化
 11 {
 12     father[x] = x;
 13     rank1[x] = 0;
 14 }
 15 
 16 int Find_Set(int x)//找根节点
 17 {
 18     int i=0;
 19     while(father[x] != x)
 20     {
 21         sign[i++] = x;
 22         x = father[x];
 23     }
 24     for(i;i>=1;i--)
 25     {
 26         father[sign[i-1]] = x;
 27     }
 28     return x;
 29 }
 30 
 31 
 32 void Union(int x,int y)//合并
 33 {
 34     x = Find_Set(x);
 35     y = Find_Set(y);
 36     if(x == y)
 37     {
 38         return;
 39     }
 40     if(rank1[x] > rank1[y])
 41     {
 42         father[y] = x;
 43     }
 44     else if(rank1[x] < rank1[y])
 45     {
 46         father[x] = y;
 47     }
 48     else if(rank1[x] ==rank1[y]) 
 49     {
 50         father[x] = y;           
 51         rank1[y]++;             
 52     }
 53 }
 54 
 55 //int num[MAX];
 56 int mark[MAX*100];
 57 bool used[MAX*100];
 58 int main()
 59 {
 60     int n,m;
 61     int Case = 0;
 62     while(cin>>n>>m,n+m)
 63     {
 64         Case++;
 65         int i;
 66         int mark_num = 0;
 67         for(i=0;i<n;i++)
 68         {
 69             Make_Set(i);
 70             mark[i] = i;
 71         //    num[i] = i;
 72         }
 73         memset(used,0,sizeof(used));
 74         while(m--)
 75         {
 76             char ch;
 77             cin>>ch;
 78             if(ch =='M')
 79             {
 80                 int a,b;
 81                 cin>>a>>b;
 82                 Union(mark[a],mark[b]);
 83             }
 84             else
 85             {
 86                 int x;
 87                 cin>>x;
 88                 mark[x] = mark_num +  n;
 89                 mark_num++;
 90                 //mark[num[x]] = num[x];
 91                 Make_Set(mark[x]);
 92             }
 93         }
 94         int sum = 0;
 95         for(i=0;i<n;i++)
 96         {
 97             if(!used[Find_Set(mark[i])])
 98             {
 99                 used[Find_Set(mark[i])] = 1;
100                 sum++; 
101             }
102         }
103         cout<<"Case #"<<Case<<": ";
104         cout<<sum<<endl;
105     }
106     return 0;
107 }

 

posted @ 2012-09-02 19:37  zx雄  阅读(239)  评论(0编辑  收藏  举报