题意:给定n个点,刚进行两种操作,将两个点合并,以及将一个点孤立,问最后点有几堆
分析:删除一个点,只是将该点独立起来,或者说将该点从所在集合中脱离,而所在集合的结构不变,若真的将该点从集合中删去,会带来很多不必要的麻烦,所以,可以反而添加一个虚拟的点代替独立出来的点,这样,用一个数组将每一个点都映射到一个虚拟的点上,之后在虚拟的点上面操作即可。当要独立一个点时,只需将该点映射到另一个原先不存在的点即可。
之后,统计集合个数有俩种方法,一个是根据集合含有的元素的个数,另一个则是统计根节点的个数。
其一
#include<iostream>
#include<algorithm>
#define M 1000000+10
using namespace std;
int f[M],n,m;
int hash1[M],r[M];
void init()
{
for(int i=0;i<M;i++)
{
f[i]=i;
hash1[i]=i;
r[i]=1;
}
}
int find(int x)
{
if(x==f[x])
return f[x];
f[x]=find(f[x]);
return f[x];
}
void Union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a==b) return ;
if(r[a]>r[b])
{
f[b]=a;
r[a]+=r[b];
r[b]=0;
}
else {
f[a]=b;
r[b]+=r[a];
r[a]=0;
}
}
int main()
{
int cas=0,a,b;
char str[5];
while(scanf("%d %d",&n,&m)==2 &&(n||m))
{
init();
while(m--)
{
scanf("%s",str);
if(str[0]=='S')
{
scanf("%d",&a);
r[find(hash1[a])]--;
hash1[a]=n++;
}
else {
scanf("%d %d",&a,&b);
Union(hash1[a],hash1[b]);
}
}
int ans=0;
for(int i=0;i<n;i++)
{
if(r[i]>0)
ans++;
}
printf("Case #%d: %d\n",++cas,ans);
}
return 0;
}
其二
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
int f[1000001],n,m;
int hash1[100001];
set<int> st;
void init()
{
for(int i=0;i<n;i++)
{
f[i]=i;
hash1[i]=i;
}
}
int find(int x)
{
if(x==f[x])
return f[x];
f[x]=find(f[x]);
return f[x];
}
void Union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a==b) return ;
f[a]=b;
}
int main()
{
int cas=0,a,b;
char str[5];
while(scanf("%d %d",&n,&m)==2 &&(n||m))
{
init();
st.clear();
int num=n;
while(m--)
{
scanf("%s",str);
if(str[0]=='S')
{
scanf("%d",&a);
hash1[a]=num++;
f[hash1[a]]=hash1[a];
}
else {
scanf("%d %d",&a,&b);
Union(hash1[a],hash1[b]);
}
}
int ans=0;
for(int i=0;i<n;i++)
{
// printf("%d %d\n",hash1[i],find(hash1[i]));
st.insert(find(hash1[i]));
}
printf("Case #%d: %d\n",++cas,st.size());
}
return 0;
}