【ybt金牌导航3-6-4】【luogu P5782】和平委员会

和平委员会

题目链接:ybt金牌导航3-6-4 / luogu P5782

题目大意

有一些人,然后 2i-1 和 2i 编号的人是同一个组别的,一定要也只能出现其中一个。
然后还有一些限制条件说某两个人不能同时出现。
问你是否有一种出现方案,使得所有条件都被满足。
如果有输出任意一组(把选的人输出出来),否则输出无解。

思路

这道题很明显看出是 2-set。

然后那同一个组别的就看做是点和反向点。
然后不能出现就是选 A 就要选 B 反向点(连边),选 B 就要选 A 反向点(连边)。

然后剩下的就是 2-set 操作了。

代码

#include<cstdio>
#include<iostream>

using namespace std;

struct node {
	int to, nxt;
}e[40001];
int n, m, x, y, tot_num, sta[20001], tmp, tot;
int le[20001], KK, dfn[20001], low[20001];
int in[20001];

int another(int x) {
	if (x & 1) return x + 1;
	return x - 1;
}

void add(int x, int y) {
	e[++KK] = (node){y, le[x]}; le[x] = KK;
}

void tarjan(int now) {
	dfn[now] = low[now] = ++tmp;
	sta[++sta[0]] = now;
	
	for (int i = le[now]; i; i = e[i].nxt)
		if (!dfn[e[i].to]) {
			tarjan(e[i].to);
			low[now] = min(low[now], low[e[i].to]);
		}
		else if (!in[e[i].to]) low[now] = min(low[now], low[e[i].to]);
	
	if (dfn[now] == low[now]) {
		in[now] = ++tot;
		while (sta[sta[0]] != now) {
			in[sta[sta[0]]] = tot;
			sta[0]--;
		}
		sta[0]--;
	}
}

int main() {
	scanf("%d %d", &n, &m);
	tot_num = n + n;
	for (int i = 1; i <= m; i++) {
		scanf("%d %d", &x, &y);
		add(x, another(y));//建图
		add(y, another(x));
	}
	
	for (int i = 1; i <= tot_num; i++)
		if (!dfn[i]) tarjan(i);
	
	for (int i = 1; i <= tot_num; i += 2)
		if (in[i] == in[another(i)]) {
			printf("NIE");
			return 0;
		}
	
	for (int i = 1; i <= tot_num; i += 2) {//输出方案(选逆拓扑序小的,也就是拓扑序大的)
		printf("%d\n", (in[i] < in[another(i)]) ? i : another(i));
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值