hdu 杭电 2473 Junk-Mail Filter
题意:输入N M,N代表开始时存在N种不同的集合数从0~(N-1),M代表有M行输入。
M X Y 代表X与Y的内容相同并在一个集合中。
S X 代表要从X当前的集合中脱离出来成为一个独立的集合。
最后要求的是不同集合数的个数。
输入数据比较大,这题最好用scanf();printf()输入 输出。
解法:并查集,在集合中删除元素,用N~N+N+M作为虚拟节点。
注意:并查集,找父节点时用压缩路径的方法,本人一开始用了递归,结果不言而知的wa。
代码:
View Code
#include<iostream> #include<algorithm> using namespace std; const int m=1400000; int father[m],sign[m],ran[100009]; //father[]记录每一个点的父节点 int find(int x) //压缩路径其中的奥妙自己领会 { int i=0; while(x!=father[x]) { sign[i++]=x; x=father[x]; } for(;i>0;i--) { father[sign[i-1]]=x; } return x; } void uion(int x,int y) { x=find(x); y=find(y); if(x!=y) father[y]=x; } int main() { int n,m; int k=1; while(scanf("%d%d",&n,&m)) { if(n==0&&m==0)break; int i; for(i=0;i<n;i++) //虚拟节点的应用 { father[i]=i+n; //将0~n-1每一虚拟一个父子节点,n~n+n+m父子节点为自身,如:当n=3,m=3时 //father[i]:3 4 5 3 4 5 6 7 8 9 } // i:0 1 2 3 4 5 6 7 8 9 for(i=n;i<=2*n+m;i++) { father[i]=i; } int step=2*n; char c; int a,b; for(i=0;i<m;i++) { cin>>c; if(c=='M') { scanf("%d%d",&a,&b); uion(a,b); } else { scanf("%d",&a); father[a]=step++; } } for(i=0;i<n;i++) { ran[i]=find(i); } sort(ran,ran+n); int sum=1; for(i=0;i<n-1;i++) { if(ran[i]!=ran[i+1]) sum++; } printf("Case #%d: %d\n",k++,sum); } return 0; }