hdu 4115 2-SAT

  1 /*
  2 题解:2-SAT
  3 一开始每一个round都有两种状态可选,并且选了每种状态有后面的限制其中一种选后另一状态的状态也被固定,
  4 十分符合2-SAT的用法;
  5 */
  6 #include <cstdio>
  7 #include <cstring>
  8 #include <iostream>
  9 #include <vector>
 10 #include <queue>
 11 
 12 #define clr(a,b) (memset(a,b,sizeof(a)))
 13 #define cpy(a,b) (memcpy(a,b,sizeof(b)))
 14 
 15 using namespace std;
 16 
 17 const int NV = 20005; // 点数要注意,后面是有两个点集
 18 const int NE = 200005; // 边也要注意加边的数量不只是限制条件的数目,因为一个限制条件可能要加几条边
 19 const int W = 0;
 20 const int R = 1;
 21 const int B = 2;
 22 
 23 int opp[NV];
 24 int in[NV];
 25 bool ans[NV];
 26 int col[NV];
 27 int n, nn, m;
 28 inline int Min(int a, int b) {return a < b ? a : b;}
 29 struct SCC {
 30     int deep,scc, top, SZ, n;
 31     struct edge {int v, next;} E[NE];
 32     int pre[NV], dep[NV], low[NV], id[NV], st[NV];
 33     bool in[NV];
 34     inline void init(int _n) {
 35         n = _n;
 36         clr(pre, -1);
 37         clr(dep, -1);
 38         clr(in,false);
 39         deep = scc = SZ = top = 0;
 40     }
 41     void tarjan(int u) {
 42         int v, i;
 43         dep[u] = low[u] = ++ deep;
 44         st[top++] = u;
 45 
 46         in[u] = true;
 47         for (i = pre[u]; i != -1; i = E[i].next) {
 48             v = E[i].v;
 49             if (dep[v] == -1) {
 50                 tarjan(v);
 51                 low[u] = Min(low[u], low[v]);
 52             }
 53             else if (in[v]) {
 54                 low[u] = Min(low[u], dep[v]);
 55             }
 56         }
 57         if (low[u] == dep[u]) {
 58             do {
 59                 v = st[--top];
 60                 in[v] = false;
 61                 id[v] = scc;
 62             } while (u != v);
 63             scc ++;
 64         }
 65     }
 66     inline void insert(int u, int v) {
 67         E[SZ].v = v;
 68         E[SZ].next = pre[u];
 69         pre[u] = SZ ++;
 70     }
 71     inline void solve() {
 72         for (int i = 0; i < n; i++) {
 73             if (dep[i] == -1) {
 74                 tarjan(i);
 75             }
 76         }
 77     }
 78 } G;
 79 int main(void) {
 80     int i, j;
 81     int x, y;
 82     int t;
 83     int alice[20005];
 84     scanf("%d",&t);
 85     for(int cas=1; cas<=t; cas++)
 86     {
 87         int n,m;
 88         scanf("%d%d", &n, &m);
 89         nn = n * 2; // 正反两个点集
 90         for (i = 0; i < nn; i++)
 91             opp[i] = (i ^ 1);
 92 
 93         G.init(nn);
 94         for(int i=0; i<nn; i+=2)
 95         {
 96             int cc;
 97             scanf("%d",&cc);
 98             switch(cc)
 99             {
100             case 1: alice[i] = 1,alice[opp[i]] = 2; break;
101             case 2: alice[i] = 2,alice[opp[i]] = 3; break;
102             case 3: alice[i] = 3,alice[opp[i]] = 1; break;
103             }
104         }
105         for (i = 0; i < m; i++) {
106             int a, b, k;
107             scanf("%d%d%d", &a, &b, &k);
108             a--;
109             a*=2;
110             b--;
111             b*=2;
112             /*
113             此处加边要注意是从0开始,而且偶数为该点集,奇数为对立点集
114             G.insert(x, opp[y]);
115             G.insert(y, opp[x]);
116             */
117             if (k)
118             {
119                 if (alice[a] == alice[b]) // 相等说明a必然要退出opp[b]才能得到正确结果,反过来亦然
120                 {
121                     G.insert(a,opp[b]);
122                     G.insert(b,opp[a]);
123                 }
124                 if (alice[a] == alice[opp[b]])
125                 {
126                     G.insert(a,b);
127                     G.insert(opp[b],opp[a]);
128                 }
129                 if (alice[opp[a]] == alice[b])
130                 {
131                     G.insert(opp[a],opp[b]);
132                     G.insert(b,a);
133                 }
134                 if (alice[opp[a]] == alice[opp[b]])
135                 {
136                     G.insert(opp[a],b);
137                     G.insert(opp[b],a);
138                 }
139             }
140             else
141             {
142                 if (alice[a] != alice[b])
143                 {
144                     G.insert(a,opp[b]);
145                     G.insert(b,opp[a]);
146                 }
147                 if (alice[a] != alice[opp[b]])
148                 {
149                     G.insert(a,b);
150                     G.insert(opp[b],opp[a]);
151                 }
152                 if (alice[opp[a]] != alice[b])
153                 {
154                     G.insert(opp[a],opp[b]);
155                     G.insert(b,a);
156                 }
157                 if (alice[opp[a]] != alice[opp[b]])
158                 {
159                     G.insert(opp[a],b);
160                     G.insert(opp[b],a);
161                 }
162             }
163         }
164         G.solve();
165         for (i = 0; i < nn; i += 2) {
166             if (G.id[i] == G.id[opp[i]]) {
167                 break;
168             }
169         }
170         if (i < nn) { // 不存在
171             printf("Case #%d: no\n",cas);
172         }
173         else
174             printf("Case #%d: yes\n",cas);
175     }
176     return 0;
177 }

 

posted @ 2014-05-09 21:19  辛力啤  阅读(335)  评论(0编辑  收藏  举报