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 }
hdu 4115 2-SAT
时间: 2024-10-10 08:50:18