HDU 2473 Junk-Mail Filter 并查集
http://acm.hdu.edu.cn/showproblem.php?pid=2473
题意:
N 是 标号为 0~(N-1)的邮件 M是有M行数据。
第二行开始为数据 当输入为M时之后跟着的两个编号表示这两封邮件都为一种垃圾邮件。
当输入为S时跟着的一个标号表示这封邮件被误判,这不是封垃圾邮件,而之前与这封邮件同时被判为垃圾邮件的那封邮件还是垃圾邮件。
输出为有多少种邮件(垃圾邮件也分很多种)。
坑爹:
1.当要将一封垃圾邮件变为普通邮件时,如果在这个垃圾邮件的树中作为根的话,那么变为普通邮件时要将剩余的垃圾邮件重新合并起来。
2.当要搜索有多少个集合(邮件种类)的时候要查找 father[i] == i 这种有多少个,但如果是 (0-1-2-3-4)(假设根为0),将01234这些点都删除了,
用 father[i] == i 来找集合的话会把前面的 (0邮件)也会算上的。
解法:
用一个代理的数组(起始跟输入的值一样),访问、删除的时候将real数组的值改变就行了(删除就将real[i]等于代理数组下标为n以后的位置),而合并就用代理数
组进行操作就行了。
View Code
1 #include<iostream> 2 using namespace std; 3 4 const int maxn = 1000000 + 100000 +10; 5 6 int real[maxn]; 7 int father[maxn]; //father[x]表示x的父节点 8 int rank[maxn]; //rank[x] 秩,表示x节点所在树的深度 9 int save[maxn]; 10 int used[maxn]; 11 12 void Make_Set() 13 { 14 memset(used,0,sizeof(used)); 15 for(int i=0;i<maxn;i++) 16 { 17 father[i]=i; //初始化一开始每个节点的父节点都为本身 18 rank[i]=1; //初始化一开始每棵树的深度为1 19 } 20 } 21 22 int findroot (int a )// 寻找x元素所在的集合也就是找子节点的根节点 23 { 24 int k=0; 25 while ( a != father[a] ) 26 { 27 save[k++] = a; 28 a = father[a]; 29 } 30 for(int i=0;i<k;i++) 31 father[ save[i] ] = a; 32 return a; 33 } 34 35 36 void Union(int x,int y) //合并两个不相交的集合,x,y分别为两个不同的集合 37 { 38 x = findroot(x); 39 y = findroot(y); 40 if(x != y) 41 { 42 if(rank[x] > rank[y]) //如果x树的深度比y树深,y树接到x树 43 { 44 father[y] = x; 45 } 46 else if(rank[x] < rank[y]) 47 { 48 father[x] = y; 49 } 50 else if(rank[x] ==rank[y]) //若两树的深度一样 51 { 52 father[x] = y; //则x树接到y树 53 rank[y]++; //此时y树的深度+1 54 } 55 } 56 } 57 58 59 int main() 60 { 61 int N; 62 int M; 63 int k = 1; 64 while(cin>>N>>M,N+M) 65 { 66 Make_Set(); 67 int i; 68 for(i =0; i<N;i++) // 让real 和 father 一一对应 69 { 70 real[i] = i; 71 } 72 int count = N - 1; // 要删除结点时在father数组中的最后一位给real[del]一个新的代理 73 while(M-- ) 74 { 75 char ch; 76 cin>>ch; 77 if(ch == 'M') 78 { 79 int x; 80 int y; 81 cin>>x>>y; 82 Union(real[x],real[y]); 83 } 84 if(ch == 'S') 85 { 86 int del; 87 cin>>del; 88 real[del] = ++count ; 89 } 90 } 91 92 int rootcount = 0; 93 //int max = N; 94 /*if(count > N - 1) 95 { 96 max = count; 97 }*/ 98 for(i =0; i<N; i++) 99 { 100 int a=findroot(real[i]); 101 if(!used[a]) 102 { 103 //printf("%d***\n",a); 104 used[a]=1; 105 rootcount++; 106 } 107 } 108 cout<<"Case #"<<k++<<": "<<rootcount<<endl; 109 } 110 return 0; 111 }

浙公网安备 33010602011771号