zoukankan      html  css  js  c++  java
  • 浅谈2-SAT(待续)

    2-SAT问题,其实是一个逻辑互斥问题。
    做了两道裸题之后仔细想来,和小时候做过的“有两个女生,如果A是女生,那么B一定不是女生。A和C性别相同,求A、B、C三人的性别。”几乎是一样的。

    对于这道题我们来分析一下。
    “如果A是女生,那么B一定不是女生”——A和B性别相反,假设“A为女生”为true,那么“B为女生”必定为false,于是一定有“B为男生”为true【注意是一定】。
    对于这句话同理可得,假设“B为女生”为true,那么“A为男生”必定为true。
    “A和C性别相同”——假设“A为女生”为true,那么“C为女生”必定为true; 假设“A为男生”为true,那么“C为男生”必定为true。
    这道题的逻辑关系十分简单,我们可以肉眼看出答案,然而对于一些逻辑关系成千上万达到1E6数量的我们不能直观看出,所以针对比较复杂的情况,人力想出了列表的方法。

          | A | B | C
    ——————————
    女   |    |    |
    ——————————
    男   |    |    |

    之后对于随机选择一个格子进行假设保证不出现互斥的情况。

    如何实现的?比如我在"A男"这一格打了勾,那么必定会在“B女”,“C男”打勾,发现不满足题意,再令A为女生重新打勾。

    下面讨论2-SAT的算法。
    先说一些概念:
    一个命题:若P则Q。
    它的逆否命题:若非Q则非P。
    这两个是等价的(大多2-SAT图是对称的,一些不对称的图指定了某个条件的真假性)

    一些“不同时为真”、“不同时为假”的逻辑关系都可以化成“若P则Q”的形式(“不同时为真”:若A为真则B为假,及其逆否命题 若B为真则A为假;若B为假则A为真,及其逆否命题 若A为假则B为真)

    对于“若P则Q”,我们从P出发,连一条边到Q,代表P如果为真Q一定为真。对于所有这样的逻辑关系都建立这样的逻辑边,之后选取一个节点进行假设赋值,如果这个点无论真假都不满足条件,该问题就无解。

    然后解题顺序:
    1.建图(把每个点拆成点A 2*i 和点B2*i+1,对于每个点A和B必定有且仅有一个为真)
    2.跑2-SAT

    下面放代码模板

     1 void _clean(){
     2 
     3     for(int i=2;i<=n*2+1;i++){
     4     g[i].clear();
     5     mark[i]=false;
     6     }
     7 }
     8 
     9 bool _dfs(int u){
    10 
    11     if(mark[u^1])return false;//如果该点的对立面为真,该点必定为假
    12     if(mark[u])return true;//如果该点之前扫过,为真,那么直接返回
    13     mark[u]=true;//如果这个点没讨论过(A/B两点均没赋值),那么把该点赋为真
    14     stk[++top]=u;//进栈,这个我还没能理解,不过最后满栈应该是top==n,栈里的都为真
    15     for(int i=0;i<g[u].size();i++)
    16     if(!_dfs(g[u][i]))return false;//该点为真,那么和这个点相连的每个点全必须为真,否则返回false
    17     return true;
    18 }
    19 
    20 bool _Twosat(){
    21     
    22     _clean();
    23     top=0;
    24     for(int i=2;i<=n*2+1;i+=2)
    25     if(!mark[i+1] && !mark[i]){//如果该点没讨论过
    26         top=0;
    27         if(!_dfs(i)){假设A点为真失败
    28         while(top)
    29             mark[stk[top--]]=false;//栈里元素全出栈,并赋值为假
    30         if(!_dfs(i+1))return false;//如果假设B点为真也失败,那么无解。
    31         }
    32         }
    33     return true;
    34 }

    补充:

    1、2-SAT问题就是一个“不能同时为真”、“若满足状态1就必定满足状态2”的逻辑问题。这一类问题的特点大多是对于每个对象可以等价成两种互斥状态。

    2、大多的2-SAT问题是对称的,即满足p->q,就一定满足-q->-p(逆否命题的互推),但也有个别例外,就是比如有一个对象与2-sat图的其他对象关联,但是题目已经决定了这个对象必须是某一个状态(不能自我假设了,这个时候可以对于这个点跑一个裸的dfs,一会儿我会讲到例题)

    下边讲几道2-SAT的题目(都只讲建图不放代码了)

    1、

    Now or laterUVALive - 3211 

    另一篇博文里有详细题解:http://www.cnblogs.com/L-Excalibur/p/8513386.html

    2、

    AstronautsUVALive - 3713

    题目链接:https://cn.vjudge.net/contest/209473#problem/K

    题目大意:有一堆宇航员要去完成任务,A任务非常伟大,只有能力值大于等于平均能力值的人才能完成,B任务是普通任务,只有能力值低于平均能力值的人才会去完成,C任务不限制条件,所有能力值的人都可以做。但是这堆宇航员互相有一些憎恨关系,如果两个宇航员互相憎恨,那么就不能给他们分配同一个任务,给出一个合理方案,如果没有合理方案输出no solution。

    解题思路:每个能力值大于等于平均值的人(以下简称第一类人)划分为两种状态a.选择任务A,b.选择任务C;能力值小于平均值(第二类人)划分为两种状态a.选择任务B,b.选择任务C。如果第一类人或第二类人有内部矛盾,那么如果其中一个为状态a,另一个一定为状态b(对称建图,不能同时为a和b,共四条)。如果第一类人和第二类人有矛盾,那么不能同时为b,一个为b另一个一定为a。

  • 相关阅读:
    数据挖掘入门系列教程(九)之基于sklearn的SVM使用
    问题_001_Vivian
    TypeScript学习笔记(五)
    TypeScript学习笔记(四)
    TypeScript学习笔记(三)
    TypeScript学习笔记(二)
    TypeScript学习笔记(一)
    使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(十)-- 发布(Windows)
    使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(九)-- 单元测试
    使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(八)-- 多环境开发
  • 原文地址:https://www.cnblogs.com/L-Excalibur/p/8504893.html
Copyright © 2011-2022 走看看