zoukankan      html  css  js  c++  java
  • 2-Sat小结

    关于2-sat,其实就是一些对于每个问题只有两种解,一般会给出问题间的关系,比如and,or,not等关系,判定是否存在解的问题。。

    具体看http://blog.csdn.net/jarjingx/article/details/8521690,该博客写得很不错的。

    下面是LRJ白书上给的2-sat,个人觉得写的很不错。。效率也很高。

     1 #define maxn 500
     2 struct TwoSat{
     3      int n;
     4      vector<int> G[maxn * 2];
     5      bool mark[maxn * 2];
     6      int S[maxn * 2], c;
     7      bool dfs(int x){ // 搜索一组解 
     8           if (mark[x^1]) return false; //出现冲突 
     9           if (mark[x]) return true;
    10           mark[x] = true;
    11           S[c++] = x;
    12           for (int i = 0; i < G[x].size(); ++i)
    13               if (!dfs(G[x][i])) return false;
    14           return true;
    15      }
    16 
    17      void init(int n){
    18           this->n = n;
    19           for (int i = 0; i < 2 * n; ++i)
    20               G[i].clear();
    21           memset(mark, 0, sizeof(mark));
    22      }
    23 
    24      void add_clause(int x, int xv, int y, int yv){
    25            x = x * 2 + xv;
    26            y = y * 2 + yv; //x,y不能同时存在,那么如果选了y,合法解必定要选x^1
    27            G[x].push_back(y^1); 
    28            G[y].push_back(x^1); 
    29      }
    30 
    31      bool solve(){
    32            for (int i = 0; i < n * 2; i += 2)
    33                if (!mark[i] && !mark[i+1]){
    34                     c = 0;
    35                     if (!dfs(i)){ //枚举2种取值都无解 
    36                           while (c > 0) mark[S[--c]] = false;
    37                           if (!dfs(i+1)) return false;
    38                     }
    39                }
    40            return true;
    41      }
    42 };

    下面是poj上经典2-sat题目:

    Poj2296:http://www.cnblogs.com/yzcstc/p/3588099.html

    PoJ2723:

    题意:

           有m道门,每到门上有两把锁,打开其中的一把锁就能打开这道门,有2n把不同的钥匙,每把对应一种锁,这些钥匙被分成n对,每队钥匙只能取其中的一把,取了一把之后另一把就会消失,然后给出每一道门对应的钥匙,求解能打开的门的最大数量.注意,必须打开这一道门才能通往下一个门

    思路:

          二分一下答案,那么就转化为判定问题。接下去就是2-sat问题了

          对于同一对钥匙a和b,属于互斥关系,添加a->~b, b->~a边

          对于同一个门的两个钥匙,属于or的 关系,即~a与~b互斥,添加~a->b, ~b->a的边

         Code:

         

      1 /*
      2  * Author:  Yzcstc
      3  * Created Time:  2014/3/8 17:14:52
      4  * File Name: Poj2723.cpp
      5  */
      6 #include<cstdio>
      7 #include<iostream>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<cmath>
     11 #include<algorithm>
     12 #include<string>
     13 #include<map>
     14 #include<set>
     15 #include<vector>
     16 #include<queue>
     17 #include<stack>
     18 #include<ctime>
     19 #define M0(x) memset(x, 0, sizeof(x))
     20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
     21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
     22 #define PB push_back
     23 #define Inf 0x3fffffff
     24 #define eps 1e-8
     25 typedef long long LL;
     26 using namespace std;
     27 #define maxn 40000
     28 int p[maxn];
     29 int X[maxn], Y[maxn], n, m, a[maxn], b[maxn];
     30 struct TwoSat{
     31      int n;
     32      vector<int> G[maxn * 2];
     33      bool mark[maxn * 2];
     34      int S[maxn * 2], c;
     35      bool dfs(int x){ // 搜索一组解 
     36           if (mark[x^1]) return false; //出现冲突 
     37           if (mark[x]) return true;
     38           mark[x] = true;
     39           S[c++] = x;
     40           for (int i = 0; i < G[x].size(); ++i)
     41               if (!dfs(G[x][i])) return false;
     42           return true;
     43      }
     44 
     45      void init(int n){
     46           this->n = n;
     47           for (int i = 0; i < 2 * n; ++i)
     48               G[i].clear();
     49           memset(mark, 0, sizeof(mark));
     50      }
     51 
     52      void add_clause(int x, int xv, int y, int yv){
     53            x = x * 2 + xv;
     54            y = y * 2 + yv; //x,y不能同时存在,那么如果选了y,合法解必定要选x^1
     55            G[x^1].push_back(y);  
     56            G[y^1].push_back(x);
     57      }
     58 
     59      bool solve(){
     60            for (int i = 0; i < n * 2; i += 2)
     61                if (!mark[i] && !mark[i+1]){
     62                     c = 0;
     63                     if (!dfs(i)){ //枚举2种取值都无解 
     64                           while (c > 0) mark[S[--c]] = false;
     65                           if (!dfs(i+1)) return false;
     66                     }
     67                }
     68            return true;
     69      }
     70 } S;
     71 
     72 void init(){
     73      int x, y;
     74      for (int i = 0; i < n; ++i){
     75            scanf("%d%d", &x, &y);
     76            X[i] = x;
     77            Y[i] = y;
     78      }
     79      n *= 2; 
     80      for (int i = 1; i <= m; ++i)
     81           scanf("%d%d", &a[i], &b[i]);
     82 }
     83 
     84 bool check(int floor){
     85      S.init(n);
     86      for (int i = 0; i < n / 2; ++i){
     87            S.add_clause(X[i], 0, Y[i], 0); 
     88          //  S.add_clause(Y[i], 1, X[i], 1);
     89      }
     90      for (int i = 1; i <= floor; ++i){
     91            S.add_clause(a[i], 1, b[i], 1); 
     92           // S.add_clause(b[i], 0, a[i], 0);  
     93      }    
     94      return S.solve();
     95 }
     96 
     97 void solve(){
     98      int l = 1, r = m, ans = 0, mid;
     99      while (l <= r){
    100           mid = (l + r) >> 1;
    101           if (check(mid)){ans = mid; l = mid + 1; }
    102           else r =  mid - 1;
    103      }
    104      printf("%d
    ", ans);
    105 }
    106 
    107 int main(){
    108    // freopen("a.in", "r", stdin);
    109   //  freopen("a.out", "w", stdout);
    110     while (scanf("%d%d", &n, &m) == 2 && n){
    111          init();
    112          solve();
    113     }
    114     fclose(stdin);  fclose(stdout);
    115     return 0;
    116 }
    View Code

    Poj2749

    题意:

           N 个牛栏,现在通过一条通道(s1,s2)把他们连起来,他们之间有一些约束关系,一些牛栏不能连在同一个点,一些牛栏必须连在同一个点,现在问有没有可能把他们都连好,而且满足所有的约束关系,如果可以,输出两个牛栏之间距离最大值的最小情况。

    思路:

          同样的二分答案。

          至于建图:假定对于某个点a,连S1,为事件a,连S2,为事件~a

                        那么,对于不能连在一起的a, b两点,显然a与b,~a与~b互斥

                        另外一种情况则反过来。。

                        还有对于任意a与b,枚举他们的连接情况,一有矛盾同样建边。具体看代码吧

        code:

       

      1 /*
      2  * Author:  Yzcstc
      3  * Created Time:  2014/3/12 14:56:50
      4  * File Name: Poj2749.cpp
      5  */
      6 #include<cstdio>
      7 #include<iostream>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<cmath>
     11 #include<algorithm>
     12 #include<string>
     13 #include<map>
     14 #include<set>
     15 #include<vector>
     16 #include<queue>
     17 #include<stack>
     18 #include<ctime>
     19 #define M0(x) memset(x, 0, sizeof(x))
     20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
     21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
     22 #define PB push_back
     23 #define Inf 0x3fffffff
     24 #define eps 1e-8
     25 #define maxn 2000
     26 typedef long long LL;
     27 using namespace std;
     28 struct TwoSat{
     29        int n;
     30        bool mark[maxn];
     31        vector<int> G[maxn];
     32        int S[maxn], c;
     33        bool dfs(int x){
     34             if (mark[x^1]) return false;
     35             if (mark[x]) return true;
     36             mark[x] = true;
     37             S[c++] = x;
     38             for (int i = 0; i < G[x].size(); ++i)
     39                  if (!dfs(G[x][i])) return false;
     40             return true;
     41        }
     42 
     43        void init(int n){
     44             this->n = n;
     45             for (int i = 0; i < 2 * n; ++i) G[i].clear();
     46             memset(mark, 0, sizeof(mark));
     47        }
     48 
     49        void add_clause(int x, int xv, int y, int yv){
     50             x = x * 2 + xv;
     51             y = y * 2 + yv;
     52             G[x].push_back(y^1);
     53             G[y].push_back(x^1);
     54        }
     55 
     56        bool solve(){
     57             for (int i = 0; i < n * 2; i += 2)
     58                 if (!mark[i] && !mark[i+1]){
     59                       c = 0;
     60                       if (!dfs(i)){
     61                            while (c > 0) mark[S[--c]] = false;
     62                            if (!dfs(i+1)) return false;
     63                       }
     64                 }
     65             return true;
     66        }
     67 } S;
     68 int X[1200], Y[1200], F[1200][2], H[1200][2], n, A, B, d[1000][2], dst;
     69 int Sx1, Sx2, Sy1, Sy2;
     70 
     71 void init(){
     72      scanf("%d%d%d%d", &Sx1, &Sy1, &Sx2, &Sy2);
     73      for (int i = 0; i < n; ++i)
     74          scanf("%d%d", &X[i], &Y[i]);
     75      for (int i = 0; i < A; ++i)
     76          scanf("%d%d", &H[i][0], &H[i][1]), --H[i][0], --H[i][1];
     77      for (int i = 0; i < B; ++i)
     78          scanf("%d%d", &F[i][0], &F[i][1]), --F[i][0], --F[i][1];
     79 }
     80 
     81 int dist(int x1, int y1, int x2, int y2){
     82     return abs(x1 - x2) + abs(y1 - y2);
     83 }
     84 
     85 void get_dist(){
     86      dst = dist(Sx1, Sy1, Sx2, Sy2);
     87      for (int i = 0; i < n; ++i){
     88          d[i][0] = dist(X[i], Y[i], Sx1, Sy1);
     89          d[i][1] = dist(X[i], Y[i], Sx2, Sy2);
     90      }
     91 }
     92 
     93 bool check(int limit){
     94      S.init(n);
     95      for (int i = 0; i < A; ++i){
     96            S.add_clause(H[i][0], 0, H[i][1], 0);
     97            S.add_clause(H[i][0], 1, H[i][1], 1);
     98      }
     99      for (int i = 0; i < B; ++i){
    100            S.add_clause(F[i][0], 0, F[i][1], 1);
    101            S.add_clause(F[i][0], 1, F[i][1], 0);
    102      }
    103      int flag = 0;
    104      for (int i = 0; i < n; ++i)
    105          for (int j = i+1; j < n; ++j){
    106               flag = 0;
    107               if (d[i][0] + d[j][0] > limit) { S.add_clause(i, 0, j, 0); flag++; }
    108               if (d[i][0] + d[j][1] + dst > limit) { S.add_clause(i, 0, j, 1); flag++; }
    109               if (d[i][1] + d[j][0] + dst > limit) { S.add_clause(i, 1, j, 0); flag++; }
    110               if (d[i][1] + d[j][1] > limit) { S.add_clause(i, 1, j, 1); flag++; }
    111               if (flag == 4) return false;
    112          }
    113      return S.solve();
    114 }
    115 
    116 void solve(){
    117      get_dist();
    118      int ans = -1;
    119      int l = 0, r = 4000000, mid;
    120      while (l <= r){
    121           mid = (l + r) >> 1;
    122           if (check(mid)){ans = mid; r = mid - 1; }
    123           else l = mid + 1;
    124      }
    125      cout << ans << endl;
    126 }
    127 
    128 int main(){
    129   //  freopen("a.in", "r", stdin);
    130    // freopen("a.out", "w", stdout);
    131     while (scanf("%d%d%d", &n, &A, &B) == 3){
    132           init();
    133           solve();
    134     }
    135     fclose(stdin);  fclose(stdout);
    136     return 0;
    137 }
    View Code

    Poj3207:

    题意:

           一个圆上有n个点,依次从0到n-1,现在给出m条线段,每条连接两个点,线段可以在圆内也可以在圆外,问能否使得所有线段都不相交。

    思路:

         简单2-sat。对于两条相交的线段建边。。

      code:

       

     1 /*
     2  * Author:  Yzcstc
     3  * Created Time:  2014/3/12 19:09:31
     4  * File Name: poj3207.cpp
     5  */
     6 #include<cstdio>
     7 #include<iostream>
     8 #include<cstring>
     9 #include<cstdlib>
    10 #include<cmath>
    11 #include<algorithm>
    12 #include<string>
    13 #include<map>
    14 #include<set>
    15 #include<vector>
    16 #include<queue>
    17 #include<stack>
    18 #include<ctime>
    19 #define M0(x) memset(x, 0, sizeof(x))
    20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
    21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
    22 #define PB push_back
    23 #define Inf 0x3fffffff
    24 #define eps 1e-8
    25 #define maxn 2014
    26 typedef long long LL;
    27 using namespace std;
    28 struct TwoSat{
    29        int n;
    30        int S[maxn], c;
    31        bool mark[maxn];
    32        vector<int> G[maxn];
    33        bool dfs(int x){
    34              if (mark[x^1]) return false;
    35              if (mark[x]) return true;
    36              mark[x] = true;
    37              S[c++] = x;
    38              for (int i = 0; i < G[x].size(); ++i)
    39                  if (!dfs(G[x][i])) return false;
    40              return true;
    41        }
    42 
    43        void init(int n){
    44              this->n = n;
    45              for (int i = 0; i < n * 2; ++i) G[i].clear();
    46              memset(mark, 0, sizeof(mark));
    47        }
    48 
    49        void add_clause(int x, int y){
    50             G[x].push_back(y^1);
    51             G[y].push_back(x^1);
    52        }
    53        bool solve(){
    54            for (int i = 0; i < n * 2; i += 2)
    55            if (!mark[i] && !mark[i+1]){
    56                   c = 0;
    57                   if (!dfs(i)){
    58                        while (c > 0) mark[S[--c]] = false;
    59                        if (!dfs(i+1)) return false;
    60                   }
    61            }
    62            return true;
    63        }
    64 } S;
    65 int m, n, X[2014], Y[2014];
    66 
    67 bool In(int a, int b, int c){
    68      if (a < b && a < c && c < b) return true;
    69      if (a > b && (c > a || c < b)) return true;
    70      return false;
    71 }
    72 void solve(){
    73      for (int i = 0; i < n; ++i)
    74         scanf("%d%d", &X[i], &Y[i]);
    75      S.init(n);
    76      for (int i = 0; i < n; ++i)
    77         for (int j = i+1; j < n; ++j)
    78              if (In(X[i], Y[i], X[j]) && In(Y[i], X[i], Y[j])
    79                  || In(X[i], Y[i], Y[j]) && In(Y[i], X[i], X[j])){
    80                      S.add_clause(i*2, j*2);
    81                      S.add_clause(i*2+1, j*2+1);
    82                  }
    83      bool ans = S.solve();
    84      if (ans) puts("panda is telling the truth...");
    85      else puts("the evil panda is lying again");
    86 }
    87 
    88 int main(){
    89    // freopen("a.in", "r", stdin);
    90   //  freopen("a.out", "w", stdout);
    91     while (scanf("%d%d", &m, &n) == 2)  solve();
    92     fclose(stdin);  fclose(stdout);
    93     return 0;
    94 }
    View Code

    Poj3648:

      题意:

             有一对新人结婚,邀请n对夫妇去参加婚礼。有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:1.每对夫妇不能坐在同一侧 2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧。如果存在一种可行的方案,输出与新娘同侧的人。

      思路:

           算是这几道题比较容易错的了 。

           对于x与y通奸,则建x->~y, y->~x的边

           而特殊的是新娘要与新郎连一条边,表示坐在对面

    code:

       

      1 /*
      2  * Author:  Yzcstc
      3  * Created Time:  2014/3/12 20:08:13
      4  * File Name: poj3468.cpp
      5  */
      6 #include<cstdio>
      7 #include<iostream>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<cmath>
     11 #include<algorithm>
     12 #include<string>
     13 #include<map>
     14 #include<set>
     15 #include<vector>
     16 #include<queue>
     17 #include<stack>
     18 #include<ctime>
     19 #define M0(x) memset(x, 0, sizeof(x))
     20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
     21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
     22 #define PB push_back
     23 #define Inf 0x3fffffff
     24 #define eps 1e-8
     25 #define maxn 50014
     26 typedef long long LL;
     27 using namespace std;
     28 struct TwoSat{
     29        int n;
     30        int S[maxn], c;
     31        bool mark[maxn];
     32        vector<int> G[maxn];
     33        bool dfs(int x){
     34              if (mark[x^1]) return false;
     35              if (mark[x]) return true;
     36              mark[x] = true;
     37              S[c++] = x;
     38              for (int i = 0; i < (int)G[x].size(); ++i)
     39                  if (!dfs(G[x][i])) return false;
     40              return true;
     41        }
     42 
     43        void init(int n){
     44              this->n = n;
     45              for (int i = 0; i < n * 2; ++i) G[i].clear();
     46              memset(mark, 0, sizeof(mark));
     47        }
     48 
     49        void add_clause(int x, int y){
     50             G[x^1].push_back(y);
     51             G[y^1].push_back(x);
     52        }
     53        bool solve(){
     54            for (int i = 0; i < n * 2; i += 2)
     55            if (!mark[i] && !mark[i+1]){
     56                   c = 0;
     57                   if (!dfs(i)){
     58                        while (c > 0) mark[S[--c]] = false;
     59                        if (!dfs(i+1)) return false;
     60                   }
     61            }
     62            return true;
     63        }
     64 } S;
     65 int n, m;
     66 
     67 void solve(){
     68      int x, y;
     69      char c1, c2;
     70      S.init(n);
     71      for (int i = 0; i < m; ++i){
     72           scanf("%d%c%d%c", &x, &c1, &y, &c2);
     73           x = x * 2;
     74           y = y * 2;
     75           if (c1 == 'h') ++x;
     76           if (c2 == 'h') ++y;
     77           S.add_clause(x, y);
     78      }
     79      S.G[1].push_back(0);
     80      if (!S.solve()){
     81             puts("bad luck");
     82             return;
     83      }
     84      for (int i = 1; i < n; ++i){
     85            if (S.mark[2*i]) printf("%dw", i);
     86            else printf("%dh", i);
     87            if (i == n-1) puts("");
     88            printf(" ");
     89      }
     90 }
     91 
     92 int main(){
     93    // freopen("a.in", "r", stdin);
     94   //  freopen("a.out", "w", stdout);
     95     while (scanf("%d%d", &n, &m) == 2 && n){
     96         // init();
     97          solve();
     98     }
     99     fclose(stdin);  fclose(stdout);
    100     return 0;
    101 }
    View Code

    poj3678:

    题意:

         有一个有向图G(V,E),每条边e(a,b)上有一个位运算符op(AND, OR或XOR)和一个值c(0或1)。

        问能不能在这个图上的每个点分配一个值X(0或1),使得每一条边e(a,b)满足  Xa op Xb =  c

    思路:

               a and b ==1 , !a->a , !b -> b

            a and b ==0 , a->!b , b->!a

            a or b ==1   ,  !a->b , !b->a

            a or b ==0   ,  a->!a , b->!b

            a xor b ==1 , a->!b,!b->a,!a->b,b->!a

            a xor b ==0 , a->b,b->a,!a->!b,!b->!a

           至于为什对于a && b == 1 要建立本身到本身反的边,是要推出矛盾。。

    code:

         

      1 /*
      2  * Author:  Yzcstc
      3  * Created Time:  2014/3/16 21:06:08
      4  * File Name: poj3678.cpp
      5  */
      6 #include<cstdio>
      7 #include<iostream>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<cmath>
     11 #include<algorithm>
     12 #include<string>
     13 #include<map>
     14 #include<set>
     15 #include<vector>
     16 #include<queue>
     17 #include<stack>
     18 #include<ctime>
     19 #define M0(x) memset(x, 0, sizeof(x))
     20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
     21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
     22 #define PB push_back
     23 #define Inf 0x3fffffff
     24 #define eps 1e-8
     25 #define maxn 4200
     26 typedef long long LL;
     27 using namespace std;
     28 struct TwoSat{
     29        int n;
     30        vector<int> G[maxn];
     31        bool mark[maxn];
     32        int c, S[maxn];
     33        bool dfs(int x){
     34              if (mark[x^1]) return false;
     35              if (mark[x]) return true;
     36              mark[x] = true;
     37              S[c++] = x;
     38              for (int i = 0; i < G[x].size(); ++i)
     39                    if (!dfs(G[x][i])) return false;
     40              return true;
     41        }
     42 
     43        void init(int n){
     44              this->n = n;
     45              memset(mark, 0, sizeof(mark));
     46              for (int i = 0; i < 2*n; ++i)
     47                   G[i].clear();
     48        }
     49 
     50        void add_clause(int x, int y){ G[x].push_back(y); }
     51 
     52        bool solve(){
     53              for (int i = 0; i < 2*n; i += 2)
     54                 if (!mark[i] && !mark[i+1]){
     55                      c = 0;
     56                      if (!dfs(i)){
     57                            while (c > 0) mark[S[--c]] = false;
     58                            if (!dfs(i+1)) return false;
     59                      }
     60                 }
     61              return true;
     62        }
     63 
     64 } S;
     65 int n, m;
     66 
     67 void solve(){
     68      char s[10];
     69      int a, b, c;
     70      S.init(n);
     71      for (int i = 0; i < m; ++i){
     72             scanf("%d%d%d%s", &a, &b, &c, &s);
     73             if (s[0] == 'A'){
     74                 if (c == 1) {  S.add_clause(a * 2, a * 2 + 1); S.add_clause(b * 2, b * 2 + 1); }
     75                 if (c == 0) {  S.add_clause(b * 2 + 1, a * 2); S.add_clause(a * 2 + 1, b * 2); }
     76             }
     77             if (s[0] == 'O'){
     78                 if (c == 1) {  S.add_clause(b * 2, a * 2 + 1); S.add_clause(a * 2, b * 2 + 1); }
     79                 if (c == 0) {  S.add_clause(a * 2 + 1, a * 2); S.add_clause(b * 2 + 1, b * 2); }
     80             }
     81             if (s[0] == 'X'){
     82                  if (c == 1) {  S.add_clause(b * 2, a * 2 + 1); S.add_clause(a * 2, b * 2 + 1);
     83                                 S.add_clause(b * 2 + 1, a * 2); S.add_clause(a * 2 + 1, b * 2);
     84                              }
     85                  if (c == 0) {  S.add_clause(b * 2, a * 2); S.add_clause(a * 2, b * 2);
     86                                 S.add_clause(b * 2 + 1, a * 2 + 1); S.add_clause(a * 2 + 1, b * 2 + 1);
     87                              }
     88             }
     89      }
     90      if (S.solve()) puts("YES");
     91      else puts("NO");
     92 }
     93 
     94 int main(){
     95    // freopen("a.in", "r", stdin);
     96    // freopen("a.out", "w", stdout);
     97     while (scanf("%d%d", &n, &m) == 2) solve();
     98     fclose(stdin);  fclose(stdout);
     99     return 0;
    100 }
    View Code

    Poj3683:

    题意:

       有一个牧师要给好几对新婚夫妇准备婚礼.,已知每对新婚夫妇的有空的时间以及婚礼持续时间..

       问是否可以让每对新婚夫妇都得到该牧师的祝福。如果可以就输出YES以及可行解 不可以就输出NO

    思路:

        典型的2-sat。只不过多了输出解。

    code:

      1 /*
      2  * Author:  Yzcstc
      3  * Created Time:  2014/3/18 18:06:09
      4  * File Name: poj3683.cpp
      5  */
      6 #include<cstdio>
      7 #include<iostream>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<cmath>
     11 #include<algorithm>
     12 #include<string>
     13 #include<map>
     14 #include<set>
     15 #include<vector>
     16 #include<queue>
     17 #include<stack>
     18 #include<ctime>
     19 #define M0(x) memset(x, 0, sizeof(x))
     20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
     21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
     22 #define PB push_back
     23 #define Inf 0x3fffffff
     24 #define maxn 8000
     25 #define eps 1e-8
     26 typedef long long LL;
     27 using namespace std;
     28 struct TwoSat{
     29        int n;
     30        vector<int> G[maxn];
     31        int c, S[maxn];
     32        bool mark[maxn];
     33        bool dfs(int x){
     34              if (mark[x^1]) return false;
     35              if (mark[x]) return true;
     36              mark[x] = true;
     37              S[c++] = x;
     38              for (int i = 0; i < G[x].size(); ++i)
     39                   if (!dfs(G[x][i])) return false;
     40              return true;
     41        }
     42 
     43        void init(int n){
     44              this->n = n;
     45              memset(mark, 0, sizeof(mark));
     46              for (int i = 0; i < 2*n; ++i)
     47                   G[i].clear();
     48        }
     49        void add_clause(int x, int y){
     50              G[x^1].push_back(y);
     51              G[y^1].push_back(x);
     52        }
     53        bool solve(){
     54              for (int i = 0; i < 2*n; i += 2)
     55                 if (!mark[i] && !mark[i+1]){
     56                        c = 0;
     57                        if (!dfs(i)){
     58                              while (c > 0) mark[S[--c]] = false;
     59                              if (!dfs(i+1)) return false;
     60                        }
     61                 }
     62              return true;
     63        }
     64 } S;
     65 int n;
     66 int St[2048], En[2048], D[2048];
     67 bool g[2048][2048];
     68 
     69 void init(){
     70      int x, y, x2, y2, z;
     71      for (int i = 0; i < n; ++i){
     72          scanf("%d:%d %d:%d %d", &x, &y, &x2, &y2, &z);
     73          D[i] = z;
     74          St[i] = x * 60 + y;
     75          En[i] = x2 * 60 + y2;
     76      }
     77 }
     78 
     79 bool check(int S1, int T1, int S2, int T2){
     80      if (S1 < T2 && S2 < T1) return true;
     81      return false;
     82 }
     83 
     84 void solve(){
     85      S.init(n);
     86      int S1, T1, S2, T2;
     87      M0(g);
     88      for (int i = 0; i < n; ++i)
     89        for (int j = i + 1; j < n; ++j){
     90              S1 = St[i],  T1 = St[i] + D[i];
     91              S2 = St[j],  T2 = St[j] + D[j];
     92              if (check(S1, T1, S2, T2)){ g[i*2][j * 2] = true; S.add_clause(i * 2, j * 2); }
     93              S1 = St[i],  T1 = St[i] + D[i];
     94              S2 = En[j] - D[j],  T2 = En[j];
     95              if (check(S1, T1, S2, T2)) { g[i*2][j*2+1] = true; S.add_clause(i * 2, j * 2 + 1);}
     96              S1 = En[i] - D[i],  T1 = En[i];
     97              S2 = St[j],  T2 = St[j] + D[j];
     98              if (check(S1, T1, S2, T2)) { g[i*2+1][j*2] = true; S.add_clause(i * 2 + 1, j * 2);}
     99              S1 = En[i] - D[i],  T1 = En[i];
    100              S2 = En[j] - D[j],  T2 = En[j];
    101              if (check(S1, T1, S2, T2)) { g[i*2+1][j*2+1] = true; S.add_clause(i * 2 + 1, j * 2 + 1);}
    102        }
    103      if (!S.solve()){puts("NO"); return;}
    104      puts("YES");
    105      vector<int> V;
    106      for (int i = 0; i < n; ++i)
    107         if (S.mark[i*2]) V.PB(i*2);
    108         else V.PB(i*2+1);
    109      bool flag = true;
    110      for (int i = 0; i < V.size(); ++i)
    111          for (int j = i+1; j < V.size(); ++j)
    112             if (g[V[i]][V[j]] || g[V[j]][V[i]]) flag = false;
    113      for (int i = 0; i < n; ++i){
    114          if (S.mark[i*2] == flag){
    115                printf("%02d:%02d %02d:%02d
    ", St[i] / 60, St[i] % 60, (St[i] + D[i]) / 60, (St[i] + D[i]) % 60);
    116                continue;
    117          }
    118          printf("%02d:%02d %02d:%02d
    ", (En[i] - D[i]) / 60, (En[i] - D[i]) % 60, En[i] / 60, En[i] % 60);
    119      }
    120 }
    121 
    122 int main(){
    123    // freopen("a.in", "r", stdin);
    124   //  freopen("a.out", "w", stdout);
    125     while (scanf("%d", &n) != EOF){
    126          init();
    127          solve();
    128     }
    129     fclose(stdin);  fclose(stdout);
    130     return 0;
    131 }
    View Code

    Poj3905

    题意:

        有n个候选人,m组要求,每组要求关系到候选人中的两个人,“+i +j”代表i和j中至少有一人被选中,“-i -j”代表i和j中至少有一人不被选中。“+i -j”代表i被选中和j不被选中这两个事件至少发生一个,“-i +j”代表i不被选中和j被选中这两个事件至少发生一个。问是否存在符合所有m项要求的方案存在。

     思路:

        简单的2-sat

    code:

     1 /*
     2  * Author:  Yzcstc
     3  * Created Time:  2014/3/19 0:06:34
     4  * File Name: poj3905.cpp
     5  */
     6 #include<cstdio>
     7 #include<iostream>
     8 #include<cstring>
     9 #include<cstdlib>
    10 #include<cmath>
    11 #include<algorithm>
    12 #include<string>
    13 #include<map>
    14 #include<set>
    15 #include<vector>
    16 #include<queue>
    17 #include<stack>
    18 #include<ctime>
    19 #define M0(x) memset(x, 0, sizeof(x))
    20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
    21 #define red(i, a, b) for (int i = (a); i >= (b); --i)
    22 #define PB push_back
    23 #define Inf 0x3fffffff
    24 #define eps 1e-8
    25 #define maxn 4000
    26 typedef long long LL;
    27 using namespace std;
    28 struct Twosat{
    29        int n;
    30        int S[maxn], c;
    31        vector<int> G[maxn];
    32        bool mark[maxn];
    33        bool dfs(int x){
    34             if (mark[x^1]) return false;
    35             if (mark[x]) return  true;
    36             mark[x] = true;
    37             S[c++] = x;
    38             for (int i = 0; i < G[x].size(); ++i)
    39                 if (!dfs(G[x][i])) return false;
    40             return true;
    41        }
    42        void init(int n){
    43             this->n = n;
    44             memset(mark, 0, sizeof(mark));
    45             for (int i = 0; i < 2 * n; ++i)
    46                  G[i].clear();
    47        }
    48        void add_clause(int x, int y){
    49             G[x^1].PB(y);
    50             G[y^1].PB(x);
    51        }
    52        bool solve(){
    53              for (int i = 0; i < 2*n; i += 2)
    54                   if (!mark[i] && !mark[i+1]){
    55                         c = 0;
    56                         if (!dfs(i)){
    57                               while (c > 0) mark[S[--c]] = false;
    58                               if (!dfs(i+1)) return false;
    59                         }
    60                   }
    61              return true;
    62        }
    63 } S;
    64 int n, m;
    65 
    66 int change(char s[], int n){
    67      int ret = 0;
    68      for (int i = 0; i < n; ++i)
    69          if(s[i] <= '9' && s[i] >= '0') ret = ret * 10 + s[i] - 48;
    70      return ret;
    71 }
    72 
    73 void solve(){
    74      int x, y;
    75      char s[20], s1[20];
    76      S.init(n);
    77      for (int i = 0; i < m; ++i){
    78            scanf("%s%s", &s, &s1);
    79            x = change(s, strlen(s)) - 1;
    80            y = change(s1, strlen(s1)) - 1;
    81            if (s[0] == '+' && s1[0] == '+') S.add_clause(x * 2 + 1, y * 2 + 1);
    82            if (s[0] == '+' && s1[0] == '-') S.add_clause(x * 2 + 1, y * 2);
    83            if (s[0] == '-' && s1[0] == '+') S.add_clause(x * 2, y * 2 + 1);
    84            if (s[0] == '-' && s1[0] == '-') S.add_clause(x * 2, y * 2);
    85      }
    86      if (S.solve()) puts("1");
    87      else puts("0");
    88 }
    89 
    90 int main(){
    91   //  freopen("a.in", "r", stdin);
    92   //  freopen("a.out", "w", stdout);
    93     while (scanf("%d%d", &n, &m) == 2) solve();
    94     fclose(stdin);  fclose(stdout);
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    CentOS查看CPU信息、位数、多核信息
    Linux常用命令大全
    chmod命令详细用法
    tar命令的详细解释
    yum和rpm命令详解
    LeetCode 241. Different Ways to Add Parentheses
    LeetCode 139. Word Break
    LeetCode 201. Bitwise AND of Numbers Range
    LeetCode 486. Predict the Winner
    LeetCode 17. Letter Combinations of a Phone Number
  • 原文地址:https://www.cnblogs.com/yzcstc/p/3610444.html
Copyright © 2011-2022 走看看