Interesting Computer Game
题目描述:
阿波罗 正在玩有趣的电脑游戏。 游戏中有 个回合,每回合,计算机会给 两个整数 和 ,并且 可以执行以下三个动作之一。
- 阿波罗无能为力。
- 如果之前所有回合都未选择整数 ,则 可以选择整数 。
- 如果在之前的所有回合中都未选择整数 ,则 可以选择整数 。
阿波罗 破解了比赛,在比赛开始之前,他已经知道了每一轮的所有候选号码。 现在他想知道最佳策略可以选择的最大整数数。我相信这对您来说是一个非常简单的问题,请帮助 解决此问题。
输入描述:
第一行是整数
,它是测试用例的数量。
每个测试用例均以包含正整数
的行开头,指示此游戏中的回合数。
接下来
行。 第
行包含两个整数
和
,表示第
个回合的两个整数。
输出描述:
对于每个测试用例,输出一行包含 # : 的行,其中 是测试用例编号,而 是答案。
样例输入:
2
6
1 2
2 3
3 4
1 4
1 3
2 4
5
1 2
1 2
1 3
2 3
5 6
样例输出:
Case #1: 4
Case #2: 4
思路:
并查集。(听说图论也可以做)
刚开始看到这道题还以为就是简单的
,结果队友
了好几遍才发现是道图论…
首先,我们需要将数据离散化,不然数据太大数组会越界。
然后,我们判断一下
和
的祖先是否一样,即判断是否有环,用一个数组记录一下祖先。
如果不一样,那么就计算一下有多少个不同的数字。
答案就是所有堆中的不重复的数字之和,如果没有环就
:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
int t,n,a[MAXN],ls[MAXN],v[MAXN],sum,ans,fa[MAXN],bian[MAXN];
int find(int x){
if(fa[x]==x) return x;
int w=fa[x];
fa[x]=find(fa[x]);
v[x]+=v[w];
bian[x]+=bian[w];
return fa[x];
}
int main(){
scanf("%d",&t);
for(int Case=1;Case<=t;Case++){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i],&a[i+n]);
ls[i]=a[i];
ls[i+n]=a[i+n];
}
sort(ls+1,ls+n*2+1);
ans=sum=unique(ls+1,ls+n*2+1)-ls-1;
memset(v,0,sizeof(v));
for(int i=1;i<=n*2;i++){
a[i]=lower_bound(ls+1,ls+sum+1,a[i])-ls;
v[a[i]]++;
}//离散化
for(int i=1;i<=sum;i++){
fa[i]=i;
bian[i]=1;
}
for(int i=1;i<=n;i++){
int fax=find(a[i]),fay=find(a[i+n]);
if(fax^fay){
v[fax]+=v[fay];
bian[fax]+=bian[fay];
fa[fay]=find(a[i]);
}
}
for(int i=1;i<=sum;i++)
if(find(i)==i&&bian[i]*2-2==v[i])
ans--;
printf("Case #%d: %d\n",Case,ans);
}
}