Description
世界上存在着N个国家,简单起见,编号从0~N-1,假如a国和b国是盟国,b国和c国是盟国,那么a国和c国也是盟国。另外每个国家都有权宣布退盟(注意,退盟后还可以再结盟)。
定义下面两个操作:
“M X Y” :X国和Y国结盟
“S X” :X国宣布退盟
Input
多组case。
每组case输入一个N和M (1 ≤ N ≤ 100000 , 1 ≤ M ≤ 1000000),N是国家数,M是操作数。
接下来输入M行操作
当N=0,M=0时,结束输入
Output
对每组case输出最终有多少个联盟,格式见样例。
Sample Input
5 6 M 0 1 M 1 2 M 1 3 S 1 M 1 2 S 3 3 1 M 1 2 0 0
Sample Output
Case #1: 3Case #2: 2
合并问题就不在说了,关键是删除问题,为了避免影响到一整个集合,所以用一个vis[]数组标记每个点的真实位置,
目的是删除一个点后,将他的位置移到原总数组的末尾
#include<stdio.h> #include<string.h> #include<algorithm> #include<set> using namespace std; int f[2000010],vis[2000010]; int p[2000010]; int getf(int v) { if(f[v]==v) return v; f[v]=getf(f[v]); return f[v]; } void merge(int u,int v) { int t1,t2; u=vis[u]; v=vis[v]; t1=getf(u); t2=getf(v); if(t1!=t2) f[t1]=t2; return ; } int main() { int n,m,a,b,k=1; char c; while(~scanf("%d%d",&n,&m)) { if(!n&&!m) break; int sum=n; for(int i=0; i<n; i++) f[i]=i,vis[i]=i; for(int i=0; i<m; i++) { getchar(); scanf("%c",&c); if(c=='M') { scanf("%d%d",&a,&b); merge(a,b); } else { scanf("%d",&a); vis[a]=sum; f[sum]=sum; sum++; } } int num=0; memset(p,0,sizeof(p)); for(int i=0;i<n;i++) { int x=getf(vis[i]); if(p[x]==0) { p[x]=1; num++; } } printf("Case #%d: ",k++); printf("%d\n",num); } return 0; }