http://poj.org/problem?id=3678
题意:
给定n个点,这些点只能取0或1。然后给出m条边,每条边四个变量 a,b,c,op op的取值为(AND,OR,XOR) 问是否存在一组解X0,X1,....Xn-1使得每条边满足Xa op Xb = c Xa,Xb表示每条边的端点。
思路:
2-sat。 将每个顶点i拆分成两个点,2*i和2*i +1 分表表示0,1。然后根据已知条件建图。建图的思想不是很清晰给出过程:
(1) A and B = 0 添加弧 A->!B , B->!A (2)A and B = 1 !A->A , !B->B (3)A or B = 0 A->!A , B->!B (4)A or B = 1 !A->B , !B->A (5)A xor B = 0 A->B , B->A , !A->!B ,!B->!A (6)A xor B = 1 A->!B, B->!A,!B->A,!A->B
然后就是2-sat判断有无解了。
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define ll long long #define inf 0x7f7f7f7f #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll long long #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define N 2007 #define M 1000007 using namespace std; struct node { int v; int next; }g[N*N]; int head[N],ct; int dfn[N],low[N]; int belong[N],stk[N]; bool isn[N]; int idx,cnt,top; int n,m; char op[10]; void add(int u,int v) { g[ct].v = v; g[ct].next = head[u]; head[u] = ct++; } //建图是关键 void build(int u,int v,int c,char *op) { if (op[0] == 'A') { if (c == 1) { add(2*u,2*u + 1); add(2*v,2*v + 1); } else { add(2*u + 1,2*v); add(2*v + 1,2*u); } } else if (op[0] == 'O') { if (c == 1) { add(2*u,2*v + 1); add(2*v,2*u + 1); } else { add(2*u + 1,2*u); add(2*v + 1,2*v); } } else if (op[0] == 'X') { if (c == 1) { add(2*u + 1,2*v); add(2*v,2*u + 1); add(2*v + 1,2*u); add(2*u,2*v + 1); } else { add(2*u + 1,2*v + 1); add(2*v + 1,2*u + 1); add(2*u,2*v); add(2*v,2*u); } } } void init() { int i; for (i = 0; i < 2*n; ++i) { dfn[i] = low[i] = -1; belong[i] = 0; isn[i] = false; } idx = cnt = top = 0; } void tarjan(int u) { int i,j; dfn[u] = low[u] = ++idx; stk[++top] = u; isn[u] = true; for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; if (dfn[v] == -1) { tarjan(v); low[u] = min(low[u],low[v]); } else if (isn[v]) { low[u] = min(low[u],dfn[v]); } } if (dfn[u] == low[u]) { cnt++; do { j = stk[top--]; isn[j] = false; belong[j] = cnt; } while (j != u); } } void solve() { int i; init(); for (i = 0; i < 2*n; ++i) { if (dfn[i] == -1) tarjan(i); } bool flag = false; for (i = 0; i < n; ++i) { if (belong[2*i] == belong[2*i + 1]) { flag = true; break; } } if (flag) printf("NO\n"); else printf("YES\n"); } int main() { //Read(); int i ; int x,y,z; while (~scanf("%d%d",&n,&m)) { CL(head,-1); ct = 0; for (i = 0; i < m; ++i) { scanf("%d%d%d%s",&x,&y,&z,op); build(x,y,z,op); } solve(); } return 0; }