HDU 2473 Junk-Mail Filter

来源:互联网 发布:夏普百视通网络电视 编辑:程序博客网 时间:2024/06/05 03:48

Junk-Mail Filter

Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6764    Accepted Submission(s): 2163


Problem Description
Recognizing junk mails is a tough task. The method used here consists of two steps:
1) Extract the common characteristics from the incoming email.
2) Use a filter matching the set of common characteristics extracted to determine whether the email is a spam.

We want to extract the set of common characteristics from the N sample junk emails available at the moment, and thus having a handy data-analyzing tool would be helpful. The tool should support the following kinds of operations:

a) “M X Y”, meaning that we think that the characteristics of spam X and Y are the same. Note that the relationship defined here is transitive, so
relationships (other than the one between X and Y) need to be created if they are not present at the moment.

b) “S X”, meaning that we think spam X had been misidentified. Your tool should remove all relationships that spam X has when this command is received; after that, spam X will become an isolated node in the relationship graph.

Initially no relationships exist between any pair of the junk emails, so the number of distinct characteristics at that time is N.
Please help us keep track of any necessary information to solve our problem.
 

Input
There are multiple test cases in the input file.
Each test case starts with two integers, N and M (1 ≤ N ≤ 105 , 1 ≤ M ≤ 106), the number of email samples and the number of operations. M lines follow, each line is one of the two formats described above.
Two successive test cases are separated by a blank line. A case with N = 0 and M = 0 indicates the end of the input file, and should not be processed by your program.
 

Output
For each test case, please print a single integer, the number of distinct common characteristics, to the console. Follow the format as indicated in the sample below.
 

Sample Input
5 6M 0 1M 1 2M 1 3S 1M 1 2S 33 1M 1 20 0
 

Sample Output
Case #1: 3Case #2: 2
 
题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=2473

最近一直在练习并查集
各种找水题
也想做些有难度的题啊
但是有心无力
现在感觉数学渣搞起ACM来确实很吃力
只能从水题开始搞起

这一个并查集的删除问题
感觉这个题很不错
可以更加深入的去了解并查集
很适合现阶段的我
循序渐进

题意是有n封邮件现在要将其含有相同的特征的放在一起
M X Y代表X,Y具有相同的特征
S Y代表Y被错判了
现在问你这两种操作完成后还有多少种的信
注意,特征可以传递 X Y 有相同特征Y Z有相同的特征
则X Y Z同时具有相同的特征
如果X Y Z中有一个被误判这剩下的两个仍然具有相同的特征

赤裸裸的模板并查集嘛
但要求中的删除操作值得去思考一下
如何才能删去一个结点而不影响其他结点的连接呢
直接删去这个点会带来一些不必要的麻烦
我们需要把这个点独立起来,封闭起来
添加一个虚拟的点来代替独立的点
              
例如上图,现在我们为每一个结点都定义一个虚拟结点
每次操作时都对结点的虚拟结点进行操作
开始时每个结点的虚拟结点都是它本身
5 -- 5,4 -- 4,3 -- 3,2 -- 2,1 -- 1
我们要删除结点3
就将结点3的虚拟结点赋值为一个大于5的数,3 -- 6
当我们再对结点3进行操作时,就相当于对结点6进行操作
然而结点6不再此集合中
完成了删除操作

上代码:
#include<stdio.h>#include<iostream>#include<set>#include<string.h>#define maxn 1000005using namespace std;int fa[maxn];//并查集 int id[maxn];//虚拟结点 int find(int x){return fa[x]==x?fa[x]:fa[x]=find(fa[x]);}int main(){int n,m,i,a,b,cnt,k=0;set<int> s;char c;while(cin>>n>>m){if(n==0&&m==0) break;for(i=0;i<maxn;i++) //并查集初始化 fa[i]=i;for(i=0;i<n;i++)//虚拟结点初始化 id[i]=i;cnt=n;while(m--){cin>>c;if(c=='M'){cin>>a>>b;a=find(id[a]);//找a的根 b=find(id[b]);//找b的根 if(a!=b)fa[a]=b;//并到同一集合 }else{cin>>a;id[a]=cnt++;//进行删除操作时虚拟结点赋值为大于等于n的数 }}s.clear();for(i=0;i<n;i++)s.insert(find(id[i]));//找每个数的根,插入到s中,看一共有几个根 printf("Case #%d: %d\n",++k,s.size());}return 0;}//只有进行删除操作时才对数组id进行操作,在此之前所有结点的虚拟结点都是它本身 //进行删除操作时,并查集fa的结构没有发生改变 

文笔有限,如有错误欢迎指正

0 0
原创粉丝点击