1 /*
2 题意:有n个数,要求满足XopY == c,操作的结果在表格中,尽管看不懂,但是实际上和平常的没有
3 区别,问是否能有n个值使得所有操作都满足
4
5 题解:2-SAT
6 题目中有位的操作,以及对于数字的选取只有选与不选,而且是限制条件,这样就会比较容易想到是
7 用2-SAT来做,关键在建图(http://blog.csdn.net/shuangde800/article/details/8876533)这个博文
8 我觉得说得比较容易理解,其实就是将所有的点都拆成两个点,然后分别组成一个集合和一个对立的
9 集合,最终我们是通过求强连通来寻找这些点是否与对立的点在同一连通分量中,如果同时出现在同
10 一个强连通之中,则表示从一个点的状态可以推出它的对立状态,这显然是错的(例如x=1可以推导出
11 x=-1),因此当我们要满足一个限制条件时,我们要做的就是通过加边使得这个条件可以满足,而且
12 对于其它的状态则要通过加边来使得它不满足(即通过加边使得这些状态肯定不可能出现),因此在加
13 边时有两个方向思考,一个是使限制条件满足,另一个是使其余状态不满足(两个应该等价吧,没有科
14 学的证明),然后就是通过求强连通查找不可能满足的点:
15
16 例子:
17 (x,y)表示两个不同的点选与不选(即是正的状态还是对立状态)
18 状态的组合有:(0,0),(0,1),(1,0),(1,1)
19 要使得xANDy为1,则需要x和y都为1,亦即(1,1)成立,其余的三个组合都不成立,则通过加边使得
20 另外三个状态不成立,要使(0,0)不满足,则需要加边(x,opp[y])表示当x为0时,y一定为1,这样
21 (0,0)的状态就被否定了(注意反向(y,opp[x])也需要加边,因为要形成强连通,单向还不能保证会形
22 成强连通,这里只是大概的理解,说得并不透彻),然后一直加边直至所有其它状态都矛盾。
23 */
24 #include <cstdio>
25 #include <cstring>
26 #include <vector>
27 #include <queue>
28
29 #define clr(a,b) (memset(a,b,sizeof(a)))
30 #define cpy(a,b) (memcpy(a,b,sizeof(b)))
31
32 using namespace std;
33
34 const int NV = 4050;
35 const int NE = 4000010;
36 const int W = 0;
37 const int R = 1;
38 const int B = 2;
39
40 int opp[NV];
41 int in[NV];
42 bool ans[NV];
43 int col[NV];
44 int nn;
45
46 inline int Min(int a, int b) {return a < b ? a : b;}
47 struct SCC {
48 int deep,scc, top, SZ, n;
49 struct edge {int v, next;} E[NE];
50 int pre[NV], dep[NV], low[NV], id[NV], st[NV];
51 bool in[NV];
52 inline void init(int _n) {
53 n = _n;
54 clr(pre, -1);
55 clr(dep, -1);
56 clr(in,false);
57 deep = scc = SZ = top = 0;
58 }
59 void tarjan(int u) {
60 int v, i;
61 dep[u] = low[u] = ++ deep;
62 st[top++] = u;
63
64 in[u] = true;
65 for (i = pre[u]; i != -1; i = E[i].next) {
66 v = E[i].v;
67 if (dep[v] == -1) {
68 tarjan(v);
69 low[u] = Min(low[u], low[v]);
70 }
71 else if (in[v]) {
72 low[u] = Min(low[u], dep[v]);
73 }
74 }
75 if (low[u] == dep[u]) {
76 do {
77 v = st[--top];
78 in[v] = false;
79 id[v] = scc;
80 } while (u != v);
81 scc ++;
82 }
83 }
84 inline void insert(int u, int v) {
85 E[SZ].v = v;
86 E[SZ].next = pre[u];
87 pre[u] = SZ ++;
88 }
89 inline void solve() {
90 for (int i = 0; i < n; i++) {
91 if (dep[i] == -1) {
92 tarjan(i);
93 }
94 }
95 }
96 } G;
97 inline void topsort() {
98 int i, j, u, v;
99 int now, id;
100 vector<int> vec[NV], gra[NV];
101 queue<int> Q, q;
102 clr(in, 0);
103 clr(col, 0);
104 for (i = 0; i < nn; i++) {
105 u = G.id[i];
106 gra[u].push_back(i);
107
108 for (j = G.pre[i]; j != -1; j = G.E[j].next) {
109 v = G.id[ G.E[j].v ];
110 if (u != v) {
111 vec[v].push_back(u);
112 in[u]++;
113 }
114 }
115 }
116 for (i = 0; i < G.scc; i++) {
117 if (in[i] == 0) {
118 Q.push(i);
119 }
120 }
121 while (!Q.empty()) {
122 now = Q.front(),Q.pop();
123 if (col[now] != W) continue;
124 col[now] = R;
125 for (i = gra[now].size() - 1; i >= 0; i--) {
126 while (!q.empty()) q.pop();
127 q.push( G.id[ opp[ gra[now][i] ] ] );
128 while (!q.empty()) {
129 id = q.front(),q.pop();
130 if (col[id] == B) continue;
131 col[id] = B;
132 for (j = vec[id].size() - 1; j >= 0; j--) {
133 q.push(vec[id][j]);
134 }
135 }
136 }
137 for (i = vec[now].size() - 1; i >= 0; i--) {
138 if (--in[ vec[now][i] ] == 0) {
139 Q.push(vec[now][i]);
140 }
141 }
142 }
143 }
144 int main(void) {
145 int i, j;
146 int x, y, c, n, m;
147 char op[10];
148 while (~scanf("%d%d", &n, &m)) {
149 nn = n * 2;
150 for (i = 0; i < nn; i++)
151 opp[i] = (i ^ 1);
152 G.init(nn);
153 for (i = 0; i < m; i++) {
154 scanf("%d%d%d%s", &x, &y, &c, op);
155 x *= 2;
156 y *= 2;
157 if(!strcmp(op, "AND")){
158 if(c){
159 G.insert(x, opp[y]), G.insert(y, opp[x]); //0, 0
160 G.insert(x, y), G.insert(opp[y], opp[x]); // 0, 1
161 G.insert(opp[x], opp[y]), G.insert(y, x); // 1, 0
162 }else{
163 G.insert(opp[x], y), G.insert(opp[y], x); // 1, 1
164 }
165 }else if(!strcmp(op, "OR")){
166 if(c){
167 G.insert(x, opp[y]), G.insert(y, opp[x]); //0, 0
168 }else{
169 G.insert(x, y), G.insert(opp[y], opp[x]); // 0, 1
170 G.insert(opp[x], opp[y]), G.insert(y, x); // 1, 0
171 G.insert(opp[x], y), G.insert(opp[y], x); // 1, 1
172 }
173 }else{ // XOR
174 if(c){
175 G.insert(x, opp[y]), G.insert(y, opp[x]); //0, 0
176 G.insert(opp[x], y), G.insert(opp[y], x); // 1, 1
177 }else{
178 G.insert(x, y), G.insert(opp[y], opp[x]); // 0, 1
179 G.insert(opp[x], opp[y]), G.insert(y, x); // 1, 0
180 }
181 }
182 }
183 G.solve();
184 for (i = 0; i < nn; i += 2) {
185 if (G.id[i] == G.id[opp[i]]) {
186 break;
187 }
188 }
189 if (i < nn)
190 printf("NO\n");
191 else
192 printf("YES\n");
193 }
194 return 0;
195 }