2-sat问题

今天才会2-sat,是不是没有救了...

Anna最近在学sat2...真是心有灵犀啊...

 

参考链接:

    http://wenku.baidu.com/view/afd6c436a32d7375a41780f2.html

 

方法:

  假如有n对pair,每对pair只能挑选一个,有些人有矛盾,不能让他们在一起

  对于p1和p2:如果有p1.x和p2.y有矛盾,即如果选择了p1.x就不能选择p2.y,即选择了p1.x就必须选择p2.x,所以就连一条边p1.x->p2.x

            同理,还有一条p2.y->p1.y

 

  无解的情况:在一定条件下,某一个人即要被选择又不能被选择

        即:在图中,存在一对pair p | p.x 和 p.y属于同一个强连通分量

 

hdu 3062 party

 1 #include <stack>
 2 #include <cstdio>
 3 #include <vector>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int maxn = 2000 + 2;
 9 const int maxm = 4000000 + 2;
10 
11 stack<int> s;
12 bool in[maxn];
13 vector<int> G[maxn];
14 int n, m, scc, Index, dfn[maxn], low[maxn], belong[maxn];
15 
16 void tarjan(int now){
17     dfn[now] = low[now] = ++ Index;
18     in[now] = true, s.push(now);
19 
20     for (int i = 0, len = G[now].size(), to; i < len; i ++){
21         to = G[now][i];
22         if (!dfn[to]){
23             tarjan(to);
24             low[now] = min(low[now], low[to]);
25         }
26 
27         else if (in[to])
28             low[now] = min(low[now], dfn[to]);
29     }
30 
31     if (low[now] == dfn[now]){
32         ++ scc;    
33 
34         int u;
35         do {
36             u = s.top();
37             s.pop(), in[u] = false;
38             belong[u] = scc;
39         } while (u ^ now);
40     }
41 }
42 
43 inline void init(){
44     memset(low, 0, sizeof low);
45     memset(dfn, 0, sizeof dfn);
46     memset(in, false, sizeof in);
47     Index = scc = 0;
48     while (not s.empty())
49         s.pop();
50     for (int i = 0; i < 2 * n; i ++)
51         G[i].clear();
52 
53     for (int i = 0, a, b, x, y, g1, g2; i < m; i ++){
54         scanf("%d %d %d %d", &a, &b, &g1, &g2);
55 
56         x = a * 2 + 1 - g1, y = b * 2 + 1 - g2;
57         a = a * 2 + g1, b = b * 2 + g2;
58 
59         G[a].push_back(y), G[b].push_back(x);
60     }
61 }
62 
63 inline bool two_sat(){
64     init();
65     for (int i = 0; i < n * 2; i ++)
66         if (!dfn[i])
67             tarjan(i);
68 
69     for (int i = 0; i < n; i ++)
70         if (belong[i * 2] == belong[i * 2 + 1])
71             return false;
72 
73     return true;
74 }
75 
76 int main(){
77     while (scanf("%d %d", &n, &m) == 2)
78         puts(two_sat() ? "YES" : "NO");
79 }
hdu 3062

poj 3678

对于每个xi,有两个选择,0还是1,建边的时候要讨论一下

  1 #include <stack>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <cstring>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int maxl = 10;
  9 const int maxn = 2000 + 2;
 10 
 11 stack<int> s;
 12 bool in[maxn];
 13 char buff[maxl];
 14 vector<int> G[maxn];
 15 int n, m, scc, Index, low[maxn], dfn[maxn], belong[maxn];
 16 
 17 inline void init(){
 18     memset(dfn, 0, sizeof dfn);
 19     memset(low, 0, sizeof low);
 20     memset(in, false, sizeof in);
 21     memset(belong, 0, sizeof belong);
 22     scc = Index = 0;
 23 
 24     for (int i = 0; i < n * 2; i ++)
 25         G[i].clear();
 26 
 27     while (!s.empty())
 28         s.pop();
 29 }
 30 
 31 void tarjan(int x){
 32     dfn[x] = low[x] = ++ Index;
 33     in[x] = true, s.push(x);
 34 
 35     for (int i = 0, to; i < G[x].size(); i ++){
 36         to = G[x][i];
 37 
 38         if (!dfn[to]){
 39             tarjan(to);
 40             low[x] = min(low[x], low[to]);
 41         }
 42 
 43         else if (in[to])
 44             low[x] = min(low[x], dfn[to]);
 45     }
 46 
 47     if (low[x] == dfn[x]){
 48         ++ scc;
 49         
 50         int u;
 51         do {
 52             u = s.top();
 53             s.pop(), in[u] = false;
 54             belong[u] = scc;
 55         } while (u ^ x);
 56     }
 57 }
 58 
 59 inline bool two_sat(){
 60     for (int i = 0; i < n * 2; i ++)
 61         if (!dfn[i])
 62             tarjan(i);
 63 
 64     for (int i = 0; i < n; i ++)
 65         if (belong[i << 1] == belong[(i << 1) | 1])
 66             return false;
 67 
 68     return true;
 69 }
 70 
 71 inline void link(int u, int v){
 72     G[u].push_back(v ^ 1);
 73     G[v].push_back(u ^ 1);
 74 }
 75 
 76 inline void type_and(int a, int b, int c){
 77     if (c){
 78         link(a << 1, b << 1);
 79         link(a << 1, (b << 1) | 1);
 80         link((a << 1) | 1, b << 1);
 81     }
 82     else 
 83         link((a << 1) | 1, (b << 1) | 1);
 84 }
 85 
 86 inline void type_or(int a, int b, int c){
 87     if (!c){
 88         link(a << 1, (b << 1) | 1);
 89         link((a << 1) | 1, b << 1);
 90         link((a << 1) | 1, (b << 1) | 1);    
 91     }
 92     else 
 93         link(a << 1, b << 1);
 94 }
 95 
 96 inline void type_xor(int a, int b, int c){
 97     if (!c){
 98         link(a << 1, (b << 1) | 1);
 99         link((a << 1) | 1, b << 1);
100     }
101     else {
102         link(a << 1, b << 1);//0 0
103         link((a << 1) | 1, (b << 1) | 1);
104     }
105 }
106 
107 int main(){
108         while (scanf("%d %d", &n, &m) == 2){
109         init();
110 
111         for (int i = 1, a, b, c; i <= m; i ++){
112             scanf("%d %d %d %s", &a, &b, &c, buff);
113 
114             if (buff[0] == 'A')
115                 type_and(a, b, c);
116 
117             if (buff[0] == 'O')
118                 type_or(a, b, c);
119 
120             if (buff[0] == 'X')
121                 type_xor(a, b, c);
122         }
123 
124         puts(two_sat() ? "YES" : "NO");
125     }
126 }
poj 3678

hdu 3622 bomb

二分答案,用2-sat来check

建图的时候:先处理处每个点的距离

对于任意两轮游戏,有两个放置位置,pair_point1 = {p1, p2}, pair_point2 = {p3, p4};

如果有dis(p1, p4) < d (即有相交的面积),就有p1 -> p3, p4->p2

  1 #include <cmath>
  2 #include <stack>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <cstring>
  6 #include <algorithm>
  7 #define _d (double)
  8 using namespace std;
  9 
 10 const double eps = 1e-4;
 11 const int maxn = 200 + 2;
 12 
 13 stack<int> s;
 14 bool in[maxn];
 15 vector<int> G[maxn];
 16 double dis[maxn][maxn];
 17 int n, scc, Index, low[maxn], dfn[maxn], belong[maxn];
 18 
 19 struct Point {
 20     int x, y;
 21 } p[maxn];
 22 
 23 inline void init(){
 24     memset(dfn, 0, sizeof dfn);
 25     memset(low, 0, sizeof low);
 26     memset(in, false, sizeof in);
 27     memset(belong, 0, sizeof belong);
 28     scc = Index = 0;
 29 
 30     for (int i = 0; i < n; i ++)
 31         G[i].clear();
 32 
 33     while (!s.empty())
 34         s.pop();
 35 }
 36 
 37 inline double get_dis(Point a, Point b){
 38     return sqrt(_d (a.x - b.x) * (a.x - b.x) + _d (a.y - b.y) * (a.y - b.y));
 39 }
 40 
 41 inline int get_partener(int a){
 42     return a % 2 == 0 ? a + 1 : a - 1;
 43 }
 44 
 45 void tarjan(int x){
 46     dfn[x] = low[x] = ++ Index;
 47     in[x] = true, s.push(x);
 48 
 49     for (int i = 0, to; i < G[x].size(); i ++){
 50         to = G[x][i];
 51 
 52         if (!dfn[to]){
 53             tarjan(to);
 54             low[x] = min(low[x], low[to]);
 55         }
 56 
 57         else if (in[to])
 58             low[x] = min(low[x], dfn[to]);
 59     }
 60 
 61     if (low[x] == dfn[x]){
 62         ++ scc;
 63         
 64         int u;
 65         do {
 66             u = s.top();
 67             s.pop(), in[u] = false;
 68             belong[u] = scc;
 69         } while (u ^ x);
 70     }
 71 }
 72 
 73 inline int cmp(double x){
 74     if (fabs(x) < eps)
 75         return 0;
 76     return x < 0 ? -1 : 1;
 77 }
 78 
 79 inline bool two_sat(double r){
 80     init();
 81 
 82     double d = r + r;
 83     for (int i = 0; i < n; i ++)
 84         for (int j = 0; j < n; j ++)
 85             if (i / 2 != j / 2 && dis[i][j] < d){
 86                 G[i].push_back(get_partener(j));
 87                 G[j].push_back(get_partener(i));
 88             }
 89 
 90     for (int i = 0; i < n; i ++)
 91         if (!dfn[i])
 92             tarjan(i);
 93 
 94     for (int i = 0; i < n; i ++)
 95         if (belong[i] == belong[get_partener(i)])
 96             return false;
 97 
 98     return true;
 99 }
100 
101 inline double search(){
102     double l = 0, r = 10000, mid;
103     while (cmp(l - r) == -1){
104         mid = (l + r) / 2.0;
105 
106         if (two_sat(mid))
107             l = mid;
108         else 
109             r = mid;
110     }
111 
112     return l;
113 }
114 
115 int main(){
116     while (~scanf("%d", &n)){
117         n *= 2;
118         for (int i = 0; i < n; i ++)
119             scanf("%d %d", &p[i].x, &p[i].y);
120 
121         for (int i = 0; i < n; i ++)
122             for (int j = i + 1; j < n; j ++)
123                 dis[i][j] = dis[j][i] = get_dis(p[i], p[j]);
124 
125         printf("%.2f
", search());
126     }
127 }
hdu 3622

 

poj 2723

二分答案,用2-sat来check

建图的时候:把每个钥匙拆成两个点,选或者不选,编号对应choose(i)和toss(i)

对于key = {a, b},有choose(a) -> toss(b), choose(b) -> toss(a)

对于lock = {a, b},有toss(a) -> choose(b), toss(b) -> choose(a)

 

  1 #include <stack>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <cstring>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int maxk = 1200 + 2;
  9 const int maxn = 1024 * 4 + 2;
 10 
 11 char ch;
 12 stack<int> s;
 13 bool in[maxn];
 14 vector<int> G[maxn];
 15 int n, m, scc, Index, dfn[maxn], low[maxn], belong[maxn];
 16 
 17 struct Pair {
 18     int a, b;
 19 } key[maxk], lock[maxk << 1];
 20 
 21 inline int next_int(){
 22     do
 23         ch = getchar();
 24     while (!(48 <= ch && ch <= 57));
 25 
 26     int ret = 0;
 27     do {
 28         ret = ret * 10 + ch - 48;
 29         ch = getchar();
 30     } while (48 <= ch && ch <= 57);
 31 
 32     return ret;
 33 }
 34 
 35 void tarjan(int now){
 36     dfn[now] = low[now] = ++ Index;
 37     in[now] = true, s.push(now);
 38 
 39     for (int i = 0, len = G[now].size(), to; i < len; i ++){
 40         to = G[now][i];
 41         if (!dfn[to]){
 42             tarjan(to);
 43             low[now] = min(low[now], low[to]);
 44         }
 45 
 46         else if (in[to])
 47             low[now] = min(low[now], dfn[to]);
 48     }
 49 
 50     if (low[now] == dfn[now]){
 51         ++ scc;    
 52 
 53         int u;
 54         do {
 55             u = s.top();
 56             s.pop(), in[u] = false;
 57             belong[u] = scc;
 58         } while (u ^ now);
 59     }
 60 }
 61 
 62 inline void clear(){
 63     memset(low, 0, sizeof low);
 64     memset(dfn, 0, sizeof dfn);
 65     memset(in, false, sizeof in);
 66     Index = scc = 0;
 67 
 68     while (not s.empty())
 69         s.pop();
 70 
 71     for (int i = 0; i < 4 * n; i ++)
 72         G[i].clear();
 73 }
 74 
 75 inline bool two_sat(int to){
 76     clear();
 77 
 78     for (int i = 0; i < n; i ++){
 79         G[key[i].a * 2].push_back(key[i].b * 2 + 1);
 80         G[key[i].b * 2].push_back(key[i].a * 2 + 1);
 81     }
 82 
 83     for (int i = 1; i <= to; i ++){
 84         G[lock[i].a * 2 + 1].push_back(lock[i].b * 2);
 85         G[lock[i].b * 2 + 1].push_back(lock[i].a * 2);
 86     }
 87 
 88     for (int i = 0; i < 4 * n; i ++)
 89         if (!dfn[i])
 90             tarjan(i);
 91 
 92     for (int i = 0; i < 2 * n; i ++)
 93         if (belong[i * 2] == belong[i * 2 + 1])
 94             return false;
 95     return true;
 96 }
 97 
 98 inline int search(){
 99     int l = 0, r = m, mid;
100     while (l < r){
101         mid = (l + r + 1) >> 1;
102 
103         if (two_sat(mid))
104             l = mid;
105         else 
106             r = mid - 1;
107     }
108 
109     return l;
110 }
111 
112 int main(){
113     while (true){
114         n = next_int(), m = next_int();
115         if (!n && !m)
116             return 0;
117 
118         for (int i = 0; i < n; i ++)
119             key[i].a = next_int(), key[i].b = next_int();
120     
121         for (int i = 1; i <= m; i ++)
122             lock[i].a = next_int(), lock[i].b = next_int();
123         
124         printf("%d
", search());
125     }
126 }
poj 2723

 

原文地址:https://www.cnblogs.com/cjhahaha/p/4122224.html