【题目大意】
给出有向图G(V, E),每条边(a,b)有一个值c(c=0或1)和运算符op,问能否找到这一张有向图,满足所有的a op b=c?
【思路】
显然是2-SAT。不过要注意一定,如a and b=1,若a=0是必定无解的。像这种情况,要连边a+n->a;同理所有类似于a or b=0,也要两边a->a+n。即无解清新要保证自己连到自己的相反情形。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 using namespace std; 8 const int MAXN=1000+50; 9 vector<int> E[MAXN]; 10 stack<int> s; 11 int low[MAXN],dfn[MAXN],cnt=0,bcnt=0; 12 int instack[MAXN],b[MAXN]; 13 int n,m; 14 15 void addedge(int u,int v) 16 { 17 E[u].push_back(v); 18 } 19 20 void tarjan(int u) 21 { 22 dfn[u]=low[u]=++cnt; 23 instack[u]=1; 24 s.push(u); 25 for (int i=0;i<E[u].size();i++) 26 { 27 int to=E[u][i]; 28 if (!instack[to]) tarjan(to),low[u]=min(low[u],low[to]); 29 else if (instack[to]==1) low[u]=min(low[u],dfn[to]); 30 } 31 32 if (dfn[u]==low[u]) 33 { 34 int x; 35 ++bcnt; 36 do 37 { 38 x=s.top();s.pop(); 39 instack[x]=2; 40 b[x]=bcnt; 41 }while (x!=u); 42 } 43 } 44 45 void init() 46 { 47 scanf("%d%d",&n,&m); 48 for (int i=0;i<m;i++) 49 { 50 int a,b,c;char op[5]; 51 scanf("%d%d%d%s",&a,&b,&c,op); 52 a++,b++; 53 if (op[0]=='A') 54 { 55 if (c==0) addedge(a,b+n),addedge(b,a+n); 56 if (c==1) addedge(a,b),addedge(b,a),addedge(a+n,a),addedge(b+n,b); 57 } 58 if (op[0]=='O') 59 { 60 if (c==0) addedge(a+n,b+n),addedge(b+n,a+n),addedge(a,a+n),addedge(b,b+n); 61 if (c==1) addedge(a+n,b),addedge(b+n,a); 62 } 63 if (op[0]=='X') 64 { 65 if (c==0) addedge(a,b),addedge(b,a),addedge(a+n,b+n),addedge(b+n,a+n); 66 if (c==1) addedge(a+n,b),addedge(b+n,a),addedge(a,b+n),addedge(b,a+n); 67 } 68 } 69 } 70 71 void solve() 72 { 73 memset(instack,0,sizeof(instack)); 74 for (int i=1;i<=2*n;i++) if (!instack[i]) tarjan(i); 75 int flag=1; 76 for (int i=1;i<=n;i++) 77 if (b[i]==b[i+n]) 78 { 79 flag=0; 80 break; 81 } 82 puts(flag?"YES":"NO"); 83 } 84 85 int main() 86 { 87 init(); 88 solve(); 89 return 0; 90 }