2sat
Posted DearDongchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2sat相关的知识,希望对你有一定的参考价值。
之前做的两发
https://vjudge.net/problem/UVALive-3211
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 2007; int t[maxn][2], n, tot, S[maxn*2], scnt; bool mark[maxn*2]; struct Edge{ int v, nxt; Edge(){} Edge(int v, int nxt):v(v), nxt(nxt){} }edge[maxn*maxn*4]; int head[maxn*2]; void addedge(int u, int v){ edge[tot] = Edge(v, head[u]); head[u] = tot++; } void conj(int x, int detx, int y, int dety){ x = 2*x+detx; y = 2*y+dety; addedge(x^1, y); addedge(y^1, x); } void build(int mid){ tot = 0; memset(head, -1, sizeof head); for(int i = 0; i < n; i++) for(int a = 0; a < 2; a++) for(int j = i+1; j < n; j++) for(int b = 0; b < 2; b++) if(fabs(t[i][a]-t[j][b]) < mid) conj(i, a^1, j, b^1); } bool dfs(int x){ if(mark[x]) return true; if(mark[x^1]) return false; mark[x] = true; S[scnt++] = x; for(int i = head[x]; ~i; i = edge[i].nxt){ int v = edge[i].v; if(!dfs(v)) return false; } return true; } bool solve(){ memset(mark, false, sizeof mark); for(int i = 0; i < 2*n; i+=2){ if(!mark[i]&&!mark[i+1]){ scnt = 0; if(!dfs(i)){ for(int j = 0; j < scnt; j++){ mark[S[j]] = false; } scnt = 0; if(!dfs(i+1)) return false; } } } return true; } int main(){ while(scanf("%d", &n)==1 && n){ for(int i = 0; i < n; i++) for(int j = 0; j < 2; j++){ scanf("%d", &t[i][j]); } int l = 0, r = 1e7; while(l < r){ int mid = (r-l+1)/2+l; build(mid); if(solve()) l = mid; else r = mid-1; } printf("%d\n", l); } return 0; } /* 10 44 156 153 182 48 109 160 201 55 186 54 207 55 165 17 58 132 160 87 197 */
https://vjudge.net/problem/UVALive-3713
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn = 100007; int age[maxn], n, m, tot, S[maxn*2], scnt; double ave; bool mark[maxn*2]; struct Edge{ int v, nxt; Edge(){} Edge(int v, int nxt):v(v), nxt(nxt){} }edge[100007*4]; int head[maxn*2]; void addedge(int u, int v){ edge[tot] = Edge(v, head[u]); head[u] = tot++; } void conj(int x, int detx, int y, int dety){ x = 2*x+detx; y = 2*y+dety; addedge(x^1, y); addedge(y^1, x); } bool dfs(int x){ if(mark[x]) return true; if(mark[x^1]) return false; mark[x] = true; S[scnt++] = x; for(int i = head[x]; ~i; i = edge[i].nxt){ int v = edge[i].v; if(!dfs(v)) return false; } return true; } bool solve(){ memset(mark, false, sizeof mark); for(int i = 0; i < 2*n; i+=2){ if(!mark[i]&&!mark[i+1]){ scnt = 0; if(!dfs(i)){ for(int j = 0; j < scnt; j++){ mark[S[j]] = false; } scnt = 0; if(!dfs(i+1)) return false; } } } return true; } int main(){ while(scanf("%d%d", &n, &m)){ tot = 0; memset(head, -1, sizeof head); if(!n&&!m) break; double sum = 0; for(int i = 0; i < n; i++){ scanf("%d", &age[i]); sum += age[i]; } ave = sum/n; while(m--){ int u, v; scanf("%d%d", &u, &v); u--; v--; if((age[u]<ave&&age[v]<ave) || (age[u]>=ave&&age[v]>=ave)){ conj(u, 0, v, 0); conj(u, 1, v, 1); } else{ conj(u, 1, v, 1); } } if(!solve()){ puts("No solution."); } else{ for(int i = 0; i < 2*n; i+=2){ if(mark[i]){ printf("C\n"); } else{ if(age[i/2]>=ave) printf("A\n"); else printf("B\n"); } } } } return 0; } /* 16 20 21 22 23 24 25 26 27 28 101 102 103 104 105 106 107 108 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 10 2 9 3 12 4 11 5 14 6 13 7 16 8 15 1 12 1 13 3 16 6 15 0 0*/
由于拆点,点数应该是2n...
每个字句a|b 加边!a -> b, !b -> a, 两条边呢...
点和边开的不够大,一言不合就爆掉了...
以上是关于2sat的主要内容,如果未能解决你的问题,请参考以下文章
POJ - 3678 - Katu Puzzle(2SAT)