• 【算法】2-sat问题【模板】


    什么是2-sat问题

     有n个布尔型变量xi,另外m个需要满足的条件。每个条件都是“xi为真/假或者xj为真/假”。这句话中的“或者”意味着两个条件中至少有一个正确。2-sat问题的目标是给每个变量赋值,使得所有的条件得到满足。

     算法的大致过程是这样的:

      构造一张有向图G,其中每个变量拆成两个结点2i和2i+1,分别表示xi为假和xi为真。最后要为每个变量选其中一个结点标记。

      对于每个“xi为假或者xj为假"这样的条件,我们连两条对称的有向边。我们上面说过,或者意味着两个中间至少有一个正确。所以如果xi为真的话,那么xj一定为假,所以我们从2*i+1向2*j连一条有向边。同样的道理,我们也从2*j+1向2*i连一条有向边。

      接下来我们逐一考虑每个没有赋值的变量,设为xi。我们先假定它为假,然后标记结点2i,并且沿着有向边标记所有能标记的结点。如果标记的过程中发现某个变量对应的两个结点都被标记,则xi假这个假定不成立,需要改为xi为真,然后重新标记。

      模板代码如下

      code from LRJ

      

     1 /*
     2 将每个变量拆成两个点2i和2i+1,分别表示xi为假和xi和真
     3 对于每个条件,连两条对称的有向边。
     4 逐一考虑没有赋值的变量,先假定它为假,然后标记结点2i,然后沿着有向边标记所有能标记的结点
     5 如果标记的过程中 发现某个变量对应的两个结点都被标记,则xi为假这个假定不成立,需要改xi为真
     6 然后重新标记
     7 */
     8 #include <cstdio>
     9 #include <cstring>
    10 #include <algorithm>
    11 #include <iostream>
    12 #include <vector>
    13 
    14 using namespace std;
    15 const int maxn=100+10;
    16 struct TwoSAT{
    17     int n;
    18     vector<int>G[2*maxn];
    19     bool mark[maxn*2];
    20     int S[maxn*2],c;
    21     bool dfs(int x){
    22         if(mark[x^1])return false;
    23         if(mark[x])return true;
    24         mark[x]=true;
    25         S[c++]=x;
    26         for(int i=0;i<G[x].size();i++){
    27             if(!dfs(G[x][i]))return false;
    28         }
    29         return true;
    30     }
    31     void init(int n){
    32         this->n=n;
    33         for(int i=0;i<n*2;i++)G[i].clear();
    34         memset(mark,0,sizeof(mark));
    35     }
    36     void add_clause(int x,int xval,int y,int yval){
    37         x=x*2+xval;
    38         y=y*2+yval;
    39         G[x^1].push_back(y);
    40         G[y^1].push_back(x);
    41     }
    42 
    43     bool solve(){
    44         for(int i=0;i<n*2;i+=2){
    45             if(!mark[i]&&!mark[i+1]){
    46                 c=0;
    47                 if(!dfs(i)){
    48                     while(c>0)mark[S[--c]]=false;
    49                     if(!dfs(i+1))return false;
    50                 }
    51             }
    52         }
    53         return true;
    54     }
    55 };
    56 int main(){
    57 return 0;
    58 }
    View Code
  • 相关阅读:
    简例 一次执行多条mysql insert语句
    javax/javaee-api/ Maven依赖
    关闭页面前提示或保存数据
    SpringMVC的controller方法上若需要参数 如User
    方正飞越 A600硬改BIOS激活win7的工具与方法。
    Win7下IE11点击无反应的解决方法
    WinXP局域网共享设置
    使用VHD,让Win XP和 Win2003 运行在内存中
    dd if=/dev/zero of=的含义是什么?Linux 下的dd命令使用详解
    win8.1点击“更改电脑设置”无反应(闪退)
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/9310860.html
Copyright © 2020-2023  润新知