Interesting Computer Game

题意:给你两组数A[n],B[n],第i次操作可以从A[i],B[i]中选择一个数,问最多可以选择多少个不同的数。

多场比赛下来,感觉翻译是个大问题,虽然翻译对了也大概率不会做,但翻译错了根本就莫得机会,英语渣哭晕在厕所。(日常牢骚)

这题我一开始想的是贪心做,然后想想不行,选择一个数对后面的影响蛮大的,然后就没然后了233。题解说把这些数对(<Ai,Bi>)看成边的端点,去求连通块的个数,然后结果是数的种类-不带环的连通块数量,我想想好像确实是这样,有环的话至少可以选到一个节点,从该节点出发可以遍历整个图(图为有向图,出发节点出发时不算经过),那么在这个图内的点都可以取到,与之相反,如果该图没有环,因为是有向图,那么不存在一个点使其遍历所有点,最多可以遍历n-1(边数)个点。

好了,还有一些细节在代码里讲

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 2e5 + 10;

int pre[N], vis[N], arr[N];

struct node {
	int x;
	int y;
}date[N];

void init(int n) {
	for (int i = 0; i <= n*2; i++) {
		pre[i] = i;
		vis[i] = 0;
	}
}

int find(int x) {//并查集
	return (x == pre[x]) ? x : pre[x] = find(pre[x]);
}

void solve(int x, int y) {//合并,判断是否有环
	int fx = find(x);
	int fy = find(y);
	if (fx == fy) {
		vis[fy] = 1;//标记环
	}
	else {
		pre[fx] = fy;
		vis[fy] |=  vis[fx];//如果其中一个点在一个有环有向图里,那么不在的那个点可以加入该有环有向图
	}
}

int main() {
	int t;
	scanf("%d", &t);
	for (int Case = 1; Case <= t; Case++) {
		int n,ans;
		scanf("%d", &n);
		init(n+2);
		for (int i = 1; i <= n; i++) {
			scanf("%d %d", &date[i].x, &date[i].y);
			arr[i*2-1] = date[i].x;//x,y过大,需要离散化
			arr[i*2] = date[i].y;
		}
		sort(arr+1,arr+1+2*n);
		int max_size = unique(arr + 1, arr + 1 + 2 * n) - (arr + 1);//将不相同的数在数组前面出现一个,得到不相同的数的个数
		for (int i = 1; i <= n; i++) {
			int l = lower_bound(arr+1,arr+1+max_size,date[i].x) - (arr + 1)+1;//第一个大于等于date[i].x的数的位置
			int r = lower_bound(arr + 1, arr + 1 + max_size, date[i].y) - (arr + 1)+1;
			solve(l, r);
		}
		ans = max_size;
		for (int i = 1; i <= max_size; i++) {
			if (pre[i] == i && !vis[i]) {//找到无环图
				ans--;
			}
		}
		printf("Case #%d: %d\n", Case, ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值