POJ-3678--2-SAT合理性判定

思路:典型的2-SAT合理性判定模板题
分类:
1、a&b=0: 若a为1,则b必为0; 若b为1,则a必为0
2、a&b=1: 若a为0,则a必为1; 若b为0,则b必为1 //这个地方需要理解一下
3、a|b=0: a=1则a必为0; b=1则b必为0
4、a|b=1: a=0则b必为1; b=0则a必为1
5、a^b=1: a=0,则b=1;a=1则b=0;b=0,则a=1;b=1,a=0
6、a^b=0: a=0,则b=0;a=1,则b=1;b=0,则a=0;b=1,则a=1

//2-SAT合理性判定
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<stack>
using namespace std;
const int N = 2e3 + 10;
const int M = 1e7 + 10;
int head[N], tot;
int n, m;
int sccno[N], scc_cnt, dfn[N], low[N], idx;
stack<int>st;
struct Edge {
	int to;
	int nxt;
}e[M];
void add(int u, int v) {
	e[++tot].to = v;
	e[tot].nxt = head[u];
	head[u] = tot;
}
void dfs(int u) {
	st.push(u);
	dfn[u] = low[u] = ++idx;
	for (int v, i = head[u]; i != -1; i = e[i].nxt) {
		v = e[i].to;
		if (!dfn[v]) {
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if (!sccno[v])
			low[u] = min(low[u], dfn[v]);
	}
	if (dfn[u] == low[u]) {
		scc_cnt++;
		while (1) {
			int x = st.top();
			st.pop();
			sccno[x] = scc_cnt;
			if (x == u)break;
		}
	}
}
bool find_scc() {
	memset(sccno, 0, sizeof(sccno));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	scc_cnt = idx = 0;
	for (int i = 1; i <= 2 * n + 1; i++) {
		if (!dfn[i])dfs(i);
	}
	for (int i = 1; i <= n; i++) {
		if (sccno[i] == sccno[i + n])return false;
	}
	return true;
}
int main() {
	scanf("%d%d", &n, &m);
	memset(head, -1, sizeof(head));
	tot = 0;
	char op[10];
	for (int a, b, c, i = 1; i <= m; i++) {
		scanf("%d%d%d%s", &a, &b, &c, op);
		a++;
		b++;
		if (op[0] == 'A') {
			if (c) {  //a&b==1: a==0,则a必为1;b==0,则b必为1
				add(a + n, a);
				add(b + n, b);
			}
			else {  //a&b==0: a==1则b必为0;b==1则a必为0
				add(a, b + n);
				add(b, a + n);
			}
		}
		else if (op[0] == 'O') {
			if (c) {  //a|b==1: a==0则b必为1;b==0则a必为1
				add(a + n, b);
				add(b + n, a);
			}
			else {  //a|b==0: a==1,则a必为0;b==1,则b必为0
				add(a, a + n);
				add(b, b + n);
			}
		}
		else if (op[0] == 'X') {
			if (c) {  //a^b==1: a==0,则b==1;a==1则b==0;b==0,则a==1;b==1,a==0
				add(a + n, b);
				add(a, b + n);
				add(b + n, a);
				add(b, a + n);
			}
			else {  //a^b==0: a==0,则b==0;a==1,则b==1;b==0,则a==0;b==1,则a==1
				add(a + n, b + n);
				add(a, b);
				add(b + n, a + n);
				add(b, a);
			}
		}
	}
	printf(find_scc() ? "YES\n" : "NO\n");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值