题目链接:http://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1435
这道题目我们可以用并查集来做,只是这道题需要我们去删除;
如果没接触过并查集可以先看一下并查集算法
这里有一篇讲并查集基本操作的博客:https://blog.csdn.net/qq_38939675/article/details/79317357
接着这道题目就只要注意怎么去处理删除了,直接贴代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int Max = 0x3f3f3f3f;
const int Min = 0xc0c0c0c0;
const int maxn = 123456;
#define mst(a) memset(a,0,sizeof(a))
int t,n,m,cnt,Case,num;
int pre[maxn],vis[maxn],real[maxn];//pre数组是用来存上级的 vis为标记数组 real为真实的位置
int find(int x)
{
int root =x;
while(root!=pre[root])//寻找上级
{
root=pre[root];
}
int j=x;
while(j!=root)//路径压缩
{
int temp=pre[j];
pre[j]=root;
j=temp;
}
return root;
}
int main()
{
while(cin>>m>>n)
{
if(m+n==0) return 0;
Case=0;
num=0;
cnt=n;
for(int i=0;i<m;i++)
{
pre[i]=i;//刚开始上级就是自己
real[i]=i;//刚开始位置就是自己
}
mst(vis);
string s;
int a,b;
for(int i=0; i<n; i++)
{
cin>>s;
if(s[0]=='M')
{
cin>>a>>b;
a=find(real[a]);
b=find(real[b]);
if(a!=b)//判断上级是否一样
{
pre[a]=b;
}
}
else {
cin>>a;
real[a]=cnt;//更新位置
pre[cnt]=cnt;//更新上级
cnt++;
}
}
for(int i=0;i<m;i++)
{
int x=find(real[i]);//寻找上级
if(!vis[x])
{
vis[x]=1;
num++;
}
}
printf("Case #%d: %d\n", ++Case,num);
}
return 0;
}
这道题目我理解了很长的时间,主要是困在于路径压缩,我举个例子吧!
比如说1和2联盟然后2和3联盟,按照道理此时1和3应该也是盟国,代码可以实现这个功能,但是实际上是在最后一次遍历所有国家的时候才将1的上级改为3的,所以说这里需要注意,我在举个例子比如1和2联盟然后2和3联盟,然后1又和4联盟,此时我们在前面比较1和4的上级是不是一样的时候就会去更新1的上级变成3所以说会有一些国家的上级会更新但是只是部分。