题目link:https://www.luogu.com.cn/problem/P3007
$2-SAT$ 裸题。
建图,设第 $i$ 号点表示支持第 $i$ 个法案,第 $i$ $+$ $n$ 号点表示反对第 $i$ 个法案。
对于每头奶牛的两个条件,因为题目要求必须满足其一,那就对奶牛的两个条件之一取反,并向另一个条件连边,表示如果不满足奶牛的其中一个要求,那必须满足另一个要求。
跑一遍 $Tarjan$ ,然后判断 $i$ 号点, $i$ $+$ $n$ 号点是否在同一个强连通分量里,如果是的话无论反对还是支持第 $i$ 个法案都会矛盾,无解。
之后如果有解的话(不满足上一行的情况),那么 $O(n$2$)$暴力判断如果支持了第 $i$ 号法案会不会矛盾,反对会不会矛盾,按情况输出。
code:
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 stack < int > pru; 5 int n, m, head[2010], low[2010], dfn[2010], col[2010], vis[2010], num, z, color; char s1[10], s2[10]; 6 struct node {int next, to;}stu[8010]; 7 void add(int x, int y) {stu[++num].next = head[x]; stu[num].to = y; head[x] = num;} 8 void tarjan(int u) 9 { 10 dfn[u] = low[u] = ++z; pru.push(u); 11 for(int i = head[u]; i; i = stu[i].next) 12 { 13 int k = stu[i].to; 14 if(!dfn[k]) tarjan(k), low[u] = min(low[u], low[k]); 15 else if(!col[k]) low[u] = min(low[u], dfn[k]); 16 } 17 if(low[u] == dfn[u]) 18 { 19 col[u] = ++color; 20 while(pru.top() != u) 21 col[pru.top()] = color, pru.pop(); 22 pru.pop(); 23 } 24 return; 25 } 26 void dfs(int u) 27 { 28 vis[u] = 1; 29 for(int i = head[u]; i; i = stu[i].next) 30 { 31 int k = stu[i].to; 32 if(!vis[k]) dfs(k); 33 } 34 return; 35 } 36 int check(int x) 37 { 38 memset(vis, 0, sizeof(vis)); dfs(x); 39 for(int i = 1; i <= n; ++i) 40 if(vis[i] && vis[i + n]) return 0; 41 return 1; 42 } 43 int main() 44 { 45 scanf("%d %d", &n, &m); 46 for(int i = 1, x, y, a, b; i <= m; ++i) 47 { 48 scanf("%d %s %d %s", &x, s1, &y, s2); 49 a = (s1[0] == 'Y'), b = (s2[0] == 'Y'); 50 add(a * n + x, !b * n + y), add(b * n + y, !a * n + x); 51 } 52 for(int i = 1; i <= 2 * n; ++i) 53 if(!dfn[i]) tarjan(i); 54 for(int i = 1; i <= n; ++i) 55 if(col[i] == col[i + n]) {puts("IMPOSSIBLE"); return 0;} 56 for(int i = 1, Tr, Fa; i <= n; ++i) 57 { 58 Tr = check(i), Fa = check(i + n); 59 if(Tr && Fa) putchar('?'); else if(Tr) putchar('Y'); else putchar('N'); 60 } 61 return 0; 62 }