HDU 3678 2-SAT

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 2e5 + 10;
int n, m, a, b, c;
char s[100];
int DFN[maxn], vis[maxn], low[maxn], Stack[maxn * 10], Belong[maxn], top, tol, cnt;
vector<int> e[maxn];
void Tarjan(int u)
{
	DFN[u] = low[u] = ++tol;
	vis[u] = true;
	Stack[++top] = u;
	int l = e[u].size();
	for (int i = 0; i < l; i++)
	{
		int v = e[u][i];
		if (!DFN[v])
		{
			Tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (vis[v] && DFN[v] < low[u]) low[u] = DFN[v];
	}
	if (DFN[u] == low[u])
	{
		cnt++; int v;
		do
		{
			v = Stack[top--];
			vis[v] = false;
			Belong[v] = cnt;
		}
		while (v != u);
	}
}
bool TwoSat(int n)
{
	for (int i = 0; i < 2 * n; i++)
		if (!DFN[i]) Tarjan(i);
	for (int i = 0; i < n; i++)
		if (Belong[2 * i] == Belong[2 * i + 1]) return false;
	return true;
}
int main(int argc, char const *argv[])
{
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++)
	{
		scanf("%d%d%d%s", &a, &b, &c, s);
		if (s[0] == 'A')
		{
			if (c)
			{
				e[2 * a + 1].push_back(2 * a);
				e[2 * b + 1].push_back(2 * b);
			}
			else
			{
				e[2 * a].push_back(2 * b + 1);
				e[2 * b].push_back(2 * a + 1);
			}
		}
		else if (s[0] == 'O')
		{
			if (c)
			{
				e[2 * a + 1].push_back(2 * b);
				e[2 * b + 1].push_back(2 * a);
			}
			else
			{
				e[2 * a].push_back(2 * a + 1);
				e[2 * b].push_back(2 * b + 1);
			}
		}
	}
	printf("%s\n", (TwoSat(n) ? "YES" : "NO"));
	return 0;
}


有一个有向图G(V,E),每条边e(a,b)上有一个位运算符op(AND, OR或XOR)和一个值c(0或1)。
问能不能在这个图上的每个点分配一个值X(0或1),使得每一条边e(a,b)满足  Xa op Xb =  c

对于两个点a和 b,   a有两个值a1=0,a2=1, b也有两个值 b1=0, b2=1.
那么枚举这两点的所有关系(a1, b1)(a1, b2)(a2, b1)(a2, b2)
然后根据位运算符看每个关系时符合条件还是不符合,如果不符合就说明这个关系时矛盾对,要添加两条边
假设是关系(a1,b1)矛盾,那么就要添加边  a1—>b2,  b1—>a2即可。

你可能感兴趣的:(HDU 3678 2-SAT)