2-SAT

P3387

题目链接

题意

  • 2-SAT板题

思路

  • 依据约束关系建图,用\(Tarjan\)跑强连通分量,如果一个值的truefalse再同一个强连通分量则无解
  • 我觉得最具有争议的地方就是洛谷的输出,输出本来按照缩点后的拓扑序,同一个值的truefalse状态选择拓扑序大的作为结果即可,即选SSC编号小的作为结果
  • 但是看贴出的题解都没有说这个问题,我按照前面n个为真,后面n个为假的状态输出,必须设置成选\(SSC\)编号大的,又按照前面n个为假,后面n个为真输出,选择编号的小的,但是和样例答案完全相反,虽然跑出的答案是相反的但也是一种合理方案,没想到竟然能A。。。

代码一(前面为真,后面为假)

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
using i64 = long long;
using ll = long long;
const int N = 1000005;
int n, m, low[N << 1], num[N << 1], sscid[N << 1], cnt, dfn;
int head[N << 1], ne[N << 2], to[N << 2], idx;
std::stack<int> st;
void init() {
	std::memset(low, 0, sizeof(low));
	std::memset(num, 0, sizeof(num));
	std::memset(sscid, 0, sizeof(sscid));
	cnt = 0;
	dfn = 0;
	std::memset(head, 0, sizeof(head));
	std::memset(ne, 0, sizeof(ne));
	std::memset(to, 0, sizeof(to));
	idx = 0;
	return;
}
void addedge(int u, int v) {
	++ idx;
	to[idx] = v;
	ne[idx] = head[u];
	head[u] = idx;
	return;
}
void dfs(int u) {
	st.push(u);
	num[u] = low[u] = ++ dfn;
	for(int i = head[u]; i; i = ne[i]) {
		int v = to[i];
		if(!num[v]) {
			dfs(v);
			low[u] = std::min(low[u], low[v]);
		} else if(!sscid[v]) {
			low[u] = std::min(low[u], num[v]);
		}
	}
	if(low[u] == num[u]) {
		++ cnt;
		while(1) {
			int v = st.top();
			st.pop();
			sscid[v] = cnt;
			if(v == u) {
				break;
			}
		}
	}
	return;
}
void tarjan() {
	for (int i = 1; i <= (n << 1); ++ i) {
		if(!num[i]) {
			dfs(i);
		}
	}
	return;
}
bool two_sat() {
	tarjan();
	for(int i = 1; i <= n; ++ i) {
		if(sscid[i] == sscid[i + n]) return false;
	}
	return true;
}
void slove() {
	init();
	std::cin >> n >> m;
	for (int i = 1; i <= m; ++ i) {
		int x, a, y, b;
		std::cin >> x >> a >> y >> b;
		int nx = x + n, ny = y + n;
		if(a == 0 && b == 0) {
			addedge(nx, y);
			addedge(ny, x);
		} else if(a == 0 && b == 1) {
			addedge(nx, ny);
			addedge(y, x);
		} else if(a == 1 && b == 0) {
			addedge(x, y);
			addedge(ny, nx);
		} else if(a == 1 && b == 1) {
			addedge(x, ny);
			addedge(y, nx);
		}
	}
	if(two_sat()) {
		std::cout << "POSSIBLE\n";
		for(int i = 1; i <= n; ++ i) {
			if(i != 1) std::cout << " ";
			std::cout << (sscid[i] < sscid[i + n] ? 0 : 1);
		}
		std::cout << "\n";
	} else {
		std::cout << "IMPOSSIBLE\n";
	}
	return;
}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	slove();
	return 0;
}

代码二(前面为假,后面为真)

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
using i64 = long long;
using ll = long long;
const int N = 1000005;
int n, m, low[N << 1], num[N << 1], sscid[N << 1], cnt, dfn;
int head[N << 1], ne[N << 2], to[N << 2], idx;
std::stack<int> st;
void init() {
	std::memset(low, 0, sizeof(low));
	std::memset(num, 0, sizeof(num));
	std::memset(sscid, 0, sizeof(sscid));
	cnt = 0;
	dfn = 0;
	std::memset(head, 0, sizeof(head));
	std::memset(ne, 0, sizeof(ne));
	std::memset(to, 0, sizeof(to));
	idx = 0;
	return;
}
void addedge(int u, int v) {
	++ idx;
	to[idx] = v;
	ne[idx] = head[u];
	head[u] = idx;
	return;
}
void dfs(int u) {
	st.push(u);
	num[u] = low[u] = ++ dfn;
	for(int i = head[u]; i; i = ne[i]) {
		int v = to[i];
		if(!num[v]) {
			dfs(v);
			low[u] = std::min(low[u], low[v]);
		} else if(!sscid[v]) {
			low[u] = std::min(low[u], num[v]);
		}
	}
	if(low[u] == num[u]) {
		++ cnt;
		while(1) {
			int v = st.top();
			st.pop();
			sscid[v] = cnt;
			if(v == u) {
				break;
			}
		}
	}
	return;
}
void tarjan() {
	for (int i = 1; i <= (n << 1); ++ i) {
		if(!num[i]) {
			dfs(i);
		}
	}
	return;
}
bool two_sat() {
	tarjan();
	for(int i = 1; i <= n; ++ i) {
		if(sscid[i] == sscid[i + n]) return false;
	}
	return true;
}
void slove() {
	init();
	std::cin >> n >> m;
	for (int i = 1; i <= m; ++ i) {
		int x, a, y, b;
		std::cin >> x >> a >> y >> b;
		int nx = x + n, ny = y + n;
		if(a == 0 && b == 0) {
			// addedge(nx, y);
			// addedge(ny, x);
			addedge(x, ny);
			addedge(y, nx);
		} else if(a == 0 && b == 1) {
			// addedge(nx, ny);
			// addedge(y, x);
			addedge(x, y);
			addedge(ny, nx);
		} else if(a == 1 && b == 0) {
			// addedge(x, y);
			// addedge(ny, nx);
			addedge(nx, ny);
			addedge(y, x);
		} else if(a == 1 && b == 1) {
			// addedge(x, ny);
			// addedge(y, nx);
			addedge(nx, y);
			addedge(ny, x);
		}
	}
	if(two_sat()) {
		std::cout << "POSSIBLE\n";
		for(int i = 1; i <= n; ++ i) {
			if(i != 1) std::cout << " ";
			std::cout << (sscid[i] < sscid[i + n] ? 1 : 0);
		}
		std::cout << "\n";
	} else {
		std::cout << "IMPOSSIBLE\n";
	}
	return;
}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	slove();
	return 0;
}
posted @ 2023-02-04 18:15  lemonsbiscuit  阅读(17)  评论(0编辑  收藏  举报