zoukankan      html  css  js  c++  java
  • 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

     

  • 相关阅读:
    WUSTOJ 1232: 矩阵乘法(C)
    JDBC(Java项目使用Oracle数据库)
    1187: 零起点学算法94——今年暑假不AC(Java)
    1223: 输出汉诺塔问题的盘子移动步骤(Java)
    软件设计师真题及解析
    Eclipse常用快捷键
    1205: 求一元二次方程的实数根(C)
    1204: 移位运算(C)
    1192: 零起点学算法99——The sum problem(C)
    1186: 零起点学算法93——改革春风吹满地(C)
  • 原文地址:https://www.cnblogs.com/cjhahaha/p/4122224.html
Copyright © 2011-2022 走看看