• 2-SAT问题的算法


    2-SAT问题:有n个bool变量x1,x2....xn,还有一些必须满足的条件。这些条件列如“x1为假或x2为真”,即“x1假x2假”、“x1假x2真”、“x1真x2真”。

    求解2-SAT问题的算法有很多,有一种效率还不错,实现方便又理解方便的算法。

    注意例子中的那个条件“x1为假或x2为真”,在x1为假的时候x2可以为任意值,但在x1为真的时候,x2为满足条件必须是真。也就是说x1为真可以推导出x2为假、x2为假可以推导出x1为真。换成一般的情况,已知xa→xb',则xb→xa'、已知xa'→xb,则xb'→xa(xi表示真xi'表示假)这个称为对称性,仔细理解下,下面证明会用到这个结论。

    我们通常建一个图G,图中节点数量为2n,把节点标号,2i节点代表着xi、2i+1代表xi'。如果xi为真的时候标记节点2i,为假的时候标记2i+1。如果知道xa→xb',则加入一条有向边2a→2b+1,同时得到xb→xa',再加入一条边2b→2a+1。

    枚举2i和2i+1都没有标记的节点,先假设xi为真,给2i标记,再进行dfs遍历,把所有可以到达的点都标记,标记过程中如果出现某个点2x和2x+1都被标记,因为不会存在x同时为真和假的情况,所以xi不能为真。再假设x2为假,给2i+1标记重复上述过程。如果xi值为真和假时都不可以,则此题无解。

    修改之前的变量可以不可以让正在枚举的点可以为真或假?答案是不可以。因为假设某个节点a被标记,dfs时遍历到a'发现矛盾,则有条路可以从i走到a’,根据对称性,a有条路可以走到i,i就不是2i和2i+1都没有被标记的节点,矛盾,所以不存在这种情况。所以dfs遍历到的点要么是已经标记过的点或者2i和2i+1都未标记的点,与之前的变量无关,所以2-SAT算法正确


    伪代码:

    bool dfs(int x){

    ____如果x节点被标记,返回真

    ____如果x^1节点被标记,返回假

    ____u为x可以到达的所有节点

    ________如果dfs(u)为假,返回假

    ____返回真

    }

    bool solve(){

    ____for i=1 to n

    ________如果2i和2i+1都为标记

    ____________如果dfs(2i)为假

    ________________清除上次遍历的节点的标记 //实现时可以用栈

    ________________如果dfs(2i+1)为假,返回假

    ____返回真

    }

  • 相关阅读:
    几个影响sql性能语句的例子
    orderby工作原理 + 最小代价取随机数
    count(*)实现原理+两阶段提交总结
    脏页flush和收缩表空间
    mysql本身用错索引+给字符串字段加索引
    Java概念辨析:equals和== equals和hashCode
    abstract方法必须在abstract类中 这句话是对的还是错的?
    java实际项目中interface和abstract interface 区别
    【timeisprecious】【JavaScript 】JavaScript String 对象
    Linux学习(三)putty,xshell使用以及密匙登陆
  • 原文地址:https://www.cnblogs.com/Chenyao2333/p/3691885.html
Copyright © 2020-2023  润新知