2014-10-16 21:08:49
思路:这道算经典的2-SAT了,各种操作。(设A0,A1分为别指派A点为真 / 假)
比较奇妙的是(1)令A点为真,则建边:A0 -> A1
(2)令A点为假,则建边:A1 -> A0
这样的话如果:A的指派为真,一旦到A0这个点那么必须到A1,这样就让A0,A1在同个SCC中,形成矛盾。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <stack> 5 using namespace std; 6 const int maxn = 1010; 7 8 int first[maxn << 1],next[maxn * maxn],ver[maxn * maxn],ecnt; 9 int low[maxn << 1],dfn[maxn << 1],sc[maxn << 1],scnt,tot; 10 int N,M; 11 stack<int> s; 12 13 void Add_edge(int u,int v){ 14 next[++ecnt] = first[u]; 15 ver[ecnt] = v; 16 first[u] = ecnt; 17 } 18 19 void Init(){ 20 memset(first,-1,sizeof(first)); 21 ecnt = tot = scnt = 0; 22 } 23 24 void Dfs1(int p){ 25 dfn[p] = low[p] = ++tot; 26 s.push(p); 27 for(int i = first[p]; i != -1; i = next[i]){ 28 int v =ver[i]; 29 if(!dfn[v]){ 30 Dfs1(v); 31 low[p] = min(low[p],low[v]); 32 } 33 else if(!sc[v]){ 34 low[p] = min(low[p],dfn[v]); 35 } 36 } 37 if(low[p] == dfn[p]){ 38 ++scnt; 39 while(1){ 40 int x = s.top(); 41 s.pop(); 42 sc[x] = scnt; 43 if(x == p) break; 44 } 45 } 46 } 47 48 void Tarjan(){ 49 memset(low,0,sizeof(low)); 50 memset(dfn,0,sizeof(dfn)); 51 memset(sc,0,sizeof(sc)); 52 while(!s.empty()) s.pop(); 53 int top = 2 * N; 54 for(int i = 0; i < top; ++i) 55 if(!dfn[i]) Dfs1(i); 56 } 57 58 int main(){ 59 int a,b,c; 60 char op[10]; 61 while(scanf("%d%d",&N,&M) != EOF){ 62 Init(); 63 for(int i = 1; i <= M; ++i){ 64 scanf("%d%d%d%s",&a,&b,&c,op); 65 if(op[0] == 'A'){ 66 if(c == 1){ 67 Add_edge(a * 2,a * 2 + 1); // true a 68 Add_edge(b * 2,b * 2 + 1); // true b 69 } 70 else{ 71 Add_edge(a * 2 + 1,b * 2); 72 Add_edge(b * 2 + 1,a * 2); 73 } 74 } 75 else if(op[0] == 'O'){ 76 if(c == 1){ 77 Add_edge(a * 2,b * 2 + 1); 78 Add_edge(b * 2,a * 2 + 1); 79 } 80 else{ 81 Add_edge(a * 2 + 1,a * 2); // not a 82 Add_edge(b * 2 + 1,b * 2); // not b 83 } 84 } 85 else{ 86 if(c == 1){ 87 Add_edge(a * 2 + 1,b * 2); 88 Add_edge(a * 2,b * 2 + 1); 89 Add_edge(b * 2 + 1,a * 2); 90 Add_edge(b * 2,a * 2 + 1); 91 } 92 else{ 93 Add_edge(a * 2,b * 2); 94 Add_edge(b * 2,a * 2); 95 Add_edge(a * 2 + 1,b * 2 + 1); 96 Add_edge(b * 2 + 1,a * 2 + 1); 97 } 98 } 99 } 100 Tarjan(); 101 int flag = 1; 102 for(int i = 0; i < N; ++i){ 103 if(sc[i * 2] == sc[i * 2 + 1]){ 104 flag = 0; 105 break; 106 } 107 } 108 if(flag) printf("YES\n"); 109 else printf("NO\n"); 110 } 111 return 0; 112 }