题目链接:http://poj.org/problem?id=3678
思路分析:该问题要求判断是否能给定每一个布尔变量一个值,使布尔变量满足某些逻辑条件;
需要根据逻辑条件来进行点与点的连接:假设两个变量为a与b,2 * a表示a的值为0的点,2 * a + 1表示a的值为1的点,则可以根据逻辑条件给出给出连接的边;
a AND b == 1 =》 a与b的值必定为1,所以2 * a –> 2 * a + 1, 2 * b –> 2 * b + 1,表示a,b必定为1;
如果a或者b为0,则2 * a 与 2 * a + 1联通,则矛盾,错误;
a AND b == 0 => 2 * a + 1 –> 2 * b, 2 * b + 1 –> 2 * a;
a OR b == 1 => 2 * a –> 2 * b + 1, 2 * b –> 2 * a + 1;
a OR b == 0 => a与b的值必定为0,所以 2 * a + 1 –> 2 * a, 2 * b + 1 –> 2 * b;
a XOR b == 1 => a与b的值不同,2 * a –> 2 * b + 1, 2 * a + 1 -> 2 * b, 2 * b + 1 –> 2 * a, 2 * b –> 2 * a + 1;
a XOR b == 1 => a与b的值相同,2 * a –> 2 * b, 2 * b –> 2 * a, 2 * a + 1 –> 2 * b + 1, 2 * b + 1 –> 2 * a + 1;
代码如下:
#include <cstdio> #include <vector> #include <cstring> #include <iostream> using namespace std; const int MAX_N = 1000 + 10; struct TwoSAT { int n; vector<int> G[2 * MAX_N]; bool mark[2 * MAX_N]; int S[2 * MAX_N], c; void Init(int n) { this->n = n; for (int i = 0; i <= 2 * n; ++i) G[i].clear(); memset(mark, 0, sizeof(mark)); } void AddClause(int x, int y, int z, char *op) { int a = 2 * x; int b = 2 * y; int c = z; if (op[0] == 'A') { if (c == 1) { G[a].push_back(a ^ 1); G[b].push_back(b ^ 1); } else { G[a ^ 1].push_back(b); G[b ^ 1].push_back(a); } } else if (op[0] == 'O') { if (c == 1) { G[a].push_back(b ^ 1); G[b].push_back(a ^ 1); } else { G[a ^ 1].push_back(a); G[b ^ 1].push_back(b); } } else { if (c == 1) { G[a].push_back(b ^ 1); G[a ^ 1].push_back(b); G[b ^ 1].push_back(a); G[b].push_back(a ^ 1); } else { G[a].push_back(b); G[b].push_back(a); G[a ^ 1].push_back(b ^ 1); G[b ^ 1].push_back(a ^ 1); } } } bool Dfs(int x) { if (mark[x ^ 1]) return false; if (mark[x]) return true; mark[x] = true; S[c++] = x; for (int i = 0; i < G[x].size(); ++i) { if (!Dfs(G[x][i])) return false; } return true; } bool Solve() { for (int i = 0; i < 2 * n; i += 2) { if (!mark[i] && !mark[i + 1]) { c = 0; if (!Dfs(i)) { while (c > 0) mark[S[--c]] = false; if (!Dfs(i + 1)) return false; } } } return true; } }; TwoSAT sat; int main() { int n, m; int a, b, c; char op[20]; while (scanf("%d %d", &n, &m) != EOF) { sat.Init(n); for (int i = 0; i < m; ++i) { scanf("%d %d %d", &a, &b, &c); scanf("%s", op); sat.AddClause(a, b, c, op); } bool ok = sat.Solve(); if (ok) printf("YES "); else printf("NO "); } return 0; }