zoukankan      html  css  js  c++  java
  • {TwoSAT}

    今天学习图论的时候,碰到了2sat问题

    虽然不是很难理解,感觉很精妙 ▄█▀█●

    用的LRJ白书上的模板。

    套路如下:

       2 - SAT就是2判定性问题,是一种特殊的逻辑判定问题。

      选择的置为1,未选的置为0

      对于2SAT,每组矛盾都会有四种情况(2*2),题目会限制一种不成立,我们要做的就是找出这一种,用逻辑连接词表示出来,然后取反,加边即可。

      具体过程白书上p324有讲,这里就不说了。

      下面附三道题,做做就知道套路了

    Party

     HDU - 3062 

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1010;
     4 struct TwoSAT
     5 {
     6     int n;
     7     vector<int> G[maxn<<1];
     8     bool mark[maxn<<1];
     9     int s[maxn<<1],c;
    10 
    11     bool dfs(int x)
    12     {
    13         if(mark[x^1]) return false;
    14         if(mark[x]) return true;
    15         mark[x]=true;
    16         s[c++]=x;
    17         for(int i=0;i<G[x].size();i++)
    18             if(!dfs(G[x][i])) return false;
    19         return true;
    20     }
    21 
    22     void init(int n)
    23     {
    24         this->n=n;
    25         for(int i=0;i<n*2;i++) G[i].clear();
    26         memset(mark,0,sizeof(mark));
    27     }
    28 
    29     void add_clause(int x,int xv,int y,int yv)
    30     {
    31         x=x*2+xv;
    32         y=y*2+yv;
    33         G[x^1].push_back(y);
    34         G[y^1].push_back(x);
    35     }
    36 
    37     bool solve()
    38     {
    39         for(int i=0;i<n*2;i+=2)
    40             if(!mark[i]&&!mark[i^1])
    41             {
    42                 c=0;
    43                 if(!dfs(i))
    44                 {
    45                     while(c>0) mark[s[--c]]=false;
    46                     if(!dfs(i+1)) return false;
    47                 }
    48             }
    49         return true;
    50     }
    51 }solver;
    52 int n,m;
    53 int age[maxn],sum;
    54 
    55 
    56 int main()
    57 {
    58     while(scanf("%d%d",&n,&m)!=EOF)
    59     {
    60         int x,y,a,b;
    61         solver.init(n);
    62         for(int i=0;i<m;i++)
    63         {
    64            scanf("%d%d%d%d",&a,&b,&x,&y);
    65            solver.add_clause(a,x^1,b,y^1);
    66         }
    67         if(solver.solve()) puts("YES");
    68         else puts("NO");
    69     }
    70     return 0;
    71 
    72 
    73 }
    View Code

    Now or later

     UVALive - 3211

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=2010;
     4 struct TwoSAT
     5 {
     6     int n;
     7     vector<int> G[maxn<<1];
     8     bool mark[maxn<<1];
     9     int s[maxn<<1],c;
    10 
    11     bool dfs(int x)
    12     {
    13         if(mark[x^1]) return false;
    14         if(mark[x]) return true;
    15         mark[x]=true;
    16         s[c++]=x;
    17         for(int i=0;i<G[x].size();i++)
    18             if(!dfs(G[x][i])) return false;
    19         return true;
    20     }
    21 
    22     void init(int n)
    23     {
    24         this->n=n;
    25         for(int i=0;i<n*2;i++) G[i].clear();
    26         memset(mark,0,sizeof(mark));
    27     }
    28 
    29     void add_clause(int x,int xv,int y,int yv)
    30     {
    31         x=x*2+xv;
    32         y=y*2+yv;
    33         G[x^1].push_back(y);
    34         G[y^1].push_back(x);
    35     }
    36 
    37     bool solve()
    38     {
    39         for(int i=0;i<n*2;i+=2)
    40             if(!mark[i]&&!mark[i^1])
    41             {
    42                 c=0;
    43                 if(!dfs(i))
    44                 {
    45                     while(c>0) mark[s[--c]]=false;
    46                     if(!dfs(i+1)) return false;
    47                 }
    48             }
    49         return true;
    50     }
    51 }solver;
    52 int n;
    53 int T[maxn][2];
    54 
    55 bool test(int diff)
    56 {
    57     solver.init(n);
    58     for(int i=0;i<n;i++) for(int a=0;a<2;a++)
    59         for(int j=i+1;j<n;j++) for(int b=0;b<2;b++)
    60         if(abs(T[i][a]-T[j][b])<diff) solver.add_clause(i,a^1,j,b^1);
    61     return solver.solve();
    62 }
    63 
    64 int main()
    65 {
    66     while(scanf("%d",&n)==1&&n)
    67     {
    68         int L=0,R=0;
    69         for(int i=0;i<n;i++) for(int a=0;a<2;a++)
    70         {
    71             scanf("%d",&T[i][a]);
    72             R=max(R,T[i][a]);
    73         }
    74         while(L<R)
    75         {
    76             int M=(R-L+1)/2+L;
    77             if(test(M)) L=M;
    78             else R=M-1;
    79         }
    80         printf("%d
    ",L);
    81     }
    82     return 0;
    83 
    84 }
    View Code

    Astronauts

     UVALive - 3713

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=100010;
     4 struct TwoSAT
     5 {
     6     int n;
     7     vector<int> G[maxn<<1];
     8     bool mark[maxn<<1];
     9     int s[maxn<<1],c;
    10 
    11     bool dfs(int x)
    12     {
    13         if(mark[x^1]) return false;
    14         if(mark[x]) return true;
    15         mark[x]=true;
    16         s[c++]=x;
    17         for(int i=0;i<G[x].size();i++)
    18             if(!dfs(G[x][i])) return false;
    19         return true;
    20     }
    21 
    22     void init(int n)
    23     {
    24         this->n=n;
    25         for(int i=0;i<n*2;i++) G[i].clear();
    26         memset(mark,0,sizeof(mark));
    27     }
    28 
    29     void add_clause(int x,int xv,int y,int yv)
    30     {
    31         x=x*2+xv;
    32         y=y*2+yv;
    33         G[x^1].push_back(y);
    34         G[y^1].push_back(x);
    35     }
    36 
    37     bool solve()
    38     {
    39         for(int i=0;i<n*2;i+=2)
    40             if(!mark[i]&&!mark[i^1])
    41             {
    42                 c=0;
    43                 if(!dfs(i))
    44                 {
    45                     while(c>0) mark[s[--c]]=false;
    46                     if(!dfs(i+1)) return false;
    47                 }
    48             }
    49         return true;
    50     }
    51 }solver;
    52 int n,m;
    53 int age[maxn],sum;
    54 
    55 bool check(int x)
    56 {
    57     return age[x]*n<sum;
    58 }
    59 
    60 int main()
    61 {
    62     while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
    63     {
    64         sum=0;
    65         for(int i=0;i<n;i++) {
    66             scanf("%d",&age[i]);
    67             sum+=age[i];
    68         }
    69         solver.init(n);
    70         for(int i=0;i<m;i++)
    71         {
    72             int a,b;
    73             scanf("%d%d",&a,&b);
    74             a--;b--;
    75             solver.add_clause(a,1,b,1);
    76             if(check(a)==check(b)) solver.add_clause(a,0,b,0);
    77         }
    78         if(!solver.solve()) printf("No solution
    ");
    79         else {
    80             for(int i=0;i<n;i++)
    81             if(solver.mark[i*2]) printf("C
    ");
    82             else if(check(i)) puts("B");
    83             else puts("A");
    84         }
    85     }
    86     return 0;
    87 }
    View Code

    基本都一样的套路。。。

  • 相关阅读:
    Effective C++ 33 避免遮掩继承而来的名称
    求子数组之和的最大值——编程之美 2.14 扩展问题 正确实现
    数据结构快速回顾——平衡二叉树 AVL (转)
    位运算符 优先级 折半搜索
    关于 二维数组指针
    C++中的单例模式(转)
    C# ThreadStart和ParameterizedThreadStart区别
    C# 实现数字字符串左补齐0的两种方法
    C# 窗口自适应窗口宽度和高度
    C# 在多线程环境中,进行安全遍历操作
  • 原文地址:https://www.cnblogs.com/yijiull/p/7219495.html
Copyright © 2011-2022 走看看