原题地址:http://poj.org/problem?id=3678
题意:给你一些边,每条边有一个值和一个运算符XOR OR AND求是否存在一些点使得所有的边根据这些运算符可以符合条件的权值.
一发AC的感觉太爽了!
思路:根据题意我我们可以知道,对于逻辑运算,只有两种取值,0或者1.那么问题就很明显的可以理解为2-sat的问题.
这题恶心就在如何建图.
我们需要分别考虑三种运算,这里就以”AND”作为例子
假设结果c=0.那么对于&&运算来说假如a==1,那么b只有1种选择,b只能等于0,不然结果就是1了,所以我们要将a==1和b==0这种情况连一条边,(由于是对称的,所以另一半就不再阐述),但是如果a==0,b的值就不是确定的了,b取0还是1都是正确的,因此对于这种情况我们是不用连边的,
如果c=1,那么和上面一样,如果a==1,那么b必须等于1,那么就需要连边.但是这里a和b的任何一个都是不允许的等于0的,因从我们要从a==0向a==1连一条边,表示a的取值不为0.(这里可以参考这题)
下面是ac代码
#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e6 + 5;
int n, m;
struct node {
int v, nxt;
} e[maxn];
int head[maxn], tot;
void add_edge(int u, int v) {
e[tot].v = v;
e[tot].nxt = head[u];
head[u] = tot++;
}
int low[maxn], dfn[maxn], belog[maxn], Stack[maxn], instack[maxn];
int index, scc, top;
void tarjan(int u) {//tarjan缩点
low[u] = dfn[u] = ++index;
instack[u] = 1;
Stack[top++] = u;
for(int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(instack[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
int v;
scc++;
do {
v = Stack[--top];
instack[v] = 0;
belog[v] = scc;
} while(u != v);
}
}
bool solver(int n) {//判断是否有可行解
CLR(dfn, 0);
CLR(instack, 0);
index = scc = top = 0;
for(int i = 0; i < n; i++) {
if(!dfn[i]) tarjan(i);
}
for(int i = 0; i < n; i += 2) {
if(belog[i] == belog[i ^ 1]) return 0;//如果对立点在同一个连通分量,那就不符合
}
return 1;
}
int main() {//偶数0,奇数1
scanf("%d%d", &n, &m);
CLR(head, -1);
tot = 0;
for(int i = 1; i <= m; i++) {
int a, b, c;
char op[10];
scanf("%d%d%d%s", &a, &b, &c, op);
if(op[0] == 'A') {
if(c == 0) {
add_edge(a << 1 | 1, b << 1);
add_edge(b << 1 | 1, a << 1);
} else {
add_edge(a << 1 | 1, b << 1 | 1);
add_edge(b << 1 | 1, a << 1 | 1);
add_edge(a << 1, a << 1 | 1);
add_edge(b << 1, b << 1 | 1);
}
} else if(op[0] == 'O') {
if(c == 0) {
add_edge(a << 1, b << 1);
add_edge(b << 1, a << 1);
add_edge(a << 1 | 1, a << 1);
add_edge(b << 1 | 1, b << 1);
} else {
add_edge(a << 1, b << 1 | 1);
add_edge(b << 1, a << 1 | 1);
}
} else {
if(c == 0) {
add_edge(a << 1, b << 1);
add_edge(b << 1, a << 1);
add_edge(a << 1 | 1, b << 1 | 1);
add_edge(b << 1 | 1, a << 1 | 1);
} else {
add_edge(a << 1, b << 1 | 1);
add_edge(a << 1 | 1, b << 1);
add_edge(b << 1, a << 1 | 1);
add_edge(b << 1 | 1, a << 1);
}
}
}
if(solver(2 * n)) printf("YES\n");
else printf("NO\n");
return 0;
}