2020暑期牛客多校训练营第八场(I)Interesting Computer Game(图论,并查集)

Interesting Computer Game

原题请看这里

题目描述:

阿波罗 ( A p o l l o ) (Apollo) (Apollo)正在玩有趣的电脑游戏。 游戏中有 N N N个回合,每回合,计算机会给 A p o l l o Apollo Apollo两个整数 ( a i (a_i (ai b i ) b_i) bi),并且 A p o l l o Apollo Apollo可以执行以下三个动作之一。

  • 阿波罗无能为力。
  • 如果之前所有回合都未选择整数 a i a_i ai,则 A p o l l o Apollo Apollo可以选择整数 a i a_i ai
  • 如果在之前的所有回合中都未选择整数 b i b_i bi,则 A p o l l o Apollo Apollo可以选择整数 b i b_i bi

阿波罗 ( A p o l l o ) (Apollo) (Apollo)破解了比赛,在比赛开始之前,他已经知道了每一轮的所有候选号码。 现在他想知道最佳策略可以选择的最大整数数。我相信这对您来说是一个非常简单的问题,请帮助 A p o l l o Apollo Apollo解决此问题。

输入描述:

第一行是整数 T ( 1 ≤ T ≤ 10 ) \mathbf{T}(1 \leq \mathbf{T} \leq 10) T(1T10),它是测试用例的数量。
每个测试用例均以包含正整数 N ( 1 ≤ N ≤ 1 0 5 ) N(1 \le N \le 10 ^ 5) N(1N105)的行开头,指示此游戏中的回合数。
接下来 N N N行。 第 i i i行包含两个整数 a i a_i ai b i ( 1 ≤ a i ≤ 1 0 9 , 1 ≤ b i ≤ 1 0 9 ) b_i(1 \le a_i \le 10 ^ 9,1 \le b_i \le 10 ^ 9) bi(1ai1091bi109),表示第 i i i个回合的两个整数。

输出描述:

对于每个测试用例,输出一行包含 C a s e Case Case # x x x: y y y的行,其中 x x x是测试用例编号,而 y y y是答案。

样例输入:

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

思路:

并查集。(听说图论也可以做)
刚开始看到这道题还以为就是简单的 t a n tan tan,结果队友 W A WA WA了好几遍才发现是道图论…
首先,我们需要将数据离散化,不然数据太大数组会越界。
然后,我们判断一下 a i a_i ai b i b_i bi的祖先是否一样,即判断是否有环,用一个数组记录一下祖先。
如果不一样,那么就计算一下有多少个不同的数字。
答案就是所有堆中的不重复的数字之和,如果没有环就 a n s − − ans-- ans

A C AC AC C o d e Code Code:

#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);
	}
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值