洛谷 P5782 [POI2001]和平委员会

B 国有 \(n\) 个党派,每个党派有 \(2\) 名代表。有的代表互相讨厌。现创立一个和平委员会,要求每个党派恰好有 \(1\) 名代表在委员会内,且所有委员都不讨厌其他委员。

2-SAT 裸题。

#include <cstdio>
#include <algorithm>

const int MAXN = 1.6e4 + 19, MAXM = 2e4 + 19;

struct Edge{
	int to, next;
}edge[MAXM << 2];

int cnt, head[MAXN << 1];

inline void add(int from, int to){
	edge[++cnt].to = to;
	edge[cnt].next = head[from];
	head[from] = cnt;
}

int ind;
int stack[MAXN << 1], top, vist[MAXN << 1];
int dfn[MAXN << 1], low[MAXN << 1];
int color[MAXN << 1], color_cnt;

void dfs(int node){
	dfn[node] = low[node] = ++ind;
	stack[++top] = node, vist[node] = true;
	for(int i = head[node]; i; i = edge[i].next)
		if(!dfn[edge[i].to]){
			dfs(edge[i].to);
			low[node] = std::min(low[node], low[edge[i].to]);
		}
		else if(vist[edge[i].to])
			low[node] = std::min(low[node], low[edge[i].to]);
	if(dfn[node] == low[node]){
		++color_cnt;
		while(stack[top + 1] != node){
			color[stack[top]] = color_cnt;
			vist[stack[top]] = false;
			--top;
		}
	}
}

int n, m;

int main(){
	std::scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i){
		add(i * 2 - 1 + n * 2, i * 2);
		add(i * 2 + n * 2, i * 2 - 1);
		add(i * 2 - 1, i * 2 + n * 2);
		add(i * 2, i * 2 - 1 + n * 2);
	}
	for(int a, b, i = 1; i <= m; ++i){
		std::scanf("%d%d", &a, &b);
		add(a, b + n * 2);
		add(b, a + n * 2);
	}
	for(int i = 1; i <= n * 4; ++i)
		if(!dfn[i])
			dfs(i);
	for(int i = 1; i <= n * 2; ++i)
		if(color[i] == color[i + n * 2])
			return std::puts("NIE"), 0;
	for(int i = 1; i <= n * 2; ++i)
		if(color[i] < color[i + n * 2])
			std::printf("%d\n", i);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/natsuka/p/12815007.html