2-sat基础详解
(大量引用《2-SAT解法浅析 -by 华中师大一附中 赵爽》《由对称性解2-SAT问题》

在实际的题目中,限制往往还有除了或以外的别的形式,这些限制也将在这篇文章中讨论。
先讨论以下两类限制的情况:
1、若x=a,则y=b
2、x=a或y=b
由于x、y都是bool变量,值要么1,要么0,所以可以通过建有向图的方式来表示这个题目。对每个bool变量x,都建立两个点,分别表示x=1和x=0。为了方便,以后的x表示图中的一个点(除非x前加“变量”两字,表示变量),~x表示点x的对应点(即另一个表示同一变量的点)。图中有了点,就要考虑边了。
设X_a (字母大写以区分上文小写字母表示内容)为变量x等于一个数a对应的点。同时下文的‘^’表示异或符号。显然对上面的两类限制都可以通过连边实现:
对于第一种限制,要增这样两条边:(X_a,Y_b)即变量x=a可推出变量y=b;(Y_(b^1),X_(a^1))即变量y不等于b可推出变量x不等于a。
对于第二种限制,就要增这样两条边:(X_(a^1),Y_b)即变量x不等于a可推出变量y等于b;(Y_(b^1),X_a)即变量y不等于b可推出变量x不等于a。
发现这些边都是对称的,即若连了一条边(x,y),则必会有边(~y,~x)(注意这里的字母是小写的)在同一时间连上。同时也发现这些边的意义也很好理解,不就是“推出”嘛。并且每种限制所连的两条边都很好地将这个限制表示了出来。那么有了一个最基本的解决问题的暴力算法了:从每个变量x开始,若它有标记,则直接看下一个变量,否则枚举它选1或选0,设选了b,并从相应的点dfs。在dfs过程中标记遍历过的变量都选什么(对正向边则标记为该边的终点;反向边则标记为该边的对应点。是的,这个dfs也要走反向边,即一切有关系的都要走)。若发现dfs过程中遍历了一组对应点,即从当前变量x选b可推出某个变量既选1又选0,这显然是矛盾的,故当前变量不能选b,要选另一个。若当前变量选1或0都不行,则无解了(这里用不用让之前的变量重新选一下,再重新枚举当前变量的取值呢?答案是不用。因为若当前变量要取枚举取1取0,则当前变量肯定与之前变量关系。因为有关系的都被打上标记了。所以之前变量的取值情况是与当前变量独立的);否则就看下一个变量: 直到看完所有变量的值后发现仍没有矛盾,则每个变量枚举的值就是答案;或发现无解情况,就记录无解信息后停止就好。
显然这个算法是很慢的,时间复杂度可达O(n*m)。除非要求一个字典序最小的取值方案,否则一般都不用这个算法。下面介绍一个更快的算法:
我们考虑图的一个强连通分量。很明显,如果我们选中强连通分量中的任何一点,那么该强连通分量中的所有其它的顶点也必须被选择。所以我们可以先求图的所有强联通分量。当我们发现若一组对应点x和~x都在同一个强连通分量时,即若变量x选1,可推出它应该选0;它选0,可推出它应该选1,这样的话变量x不管怎么选都是矛盾的,则该2-sat无解。若没有这样的情况,那么我就叫他“前置合法”了,即已经满足了有解的前提之一。前置合法后,设原图为G,缩点后的图为G',然后,我们把G'中的所有弧反向,得到图G′′。由于已经进行了缩点的操作,因此G′′中一定不存在圈,也就是说,G''具有拓扑结构。我们把G中所有顶点置为“未着色”。按照拓扑顺序重复下面的操作:
1、选择第一个未着色的顶点u。把u染成红色。
2、把所有与u矛盾的顶点(如果存在x,~x∈
,
前置合法时,k=1建的边不会影响强连通分量的对称性。(因为这条边的起点与终点不会在同一个强联通分量里)。
证明正确性前先了解几个定理:
1、
2、
3、
下面证明一下该算法的正确性:
一、
二、
1、
个人认为《2-SAT解法浅析》中有关二、1的证明是不正确的,这里可以举出一个反例:
所以下文给出作者个人的关于二、1的证明:
2、
故该算法是正确的。时间复杂度为O(n)(tarjan为O(n),拓扑排序为O(n),染色为O(n)(染色要注意不染重复的点,否则就可能变成O(n的平方))。故总复杂度也为O(n)(实际上,更准确的说,这里的n为n*2))
其实还有一个常数的优化:
故前置合法时必有解
故前置合法时,每个变量选他对应点中拓补序大的点,一定会得到一组解。这样的话就不用求完拓补序后再染色了。
再仔细考虑一下,发现tarjan的缩点的顺序正是一个反的拓补序,所以可以记录他tarjan的顺序,这样连拓扑序也不用求了。
代码
2-sat基础详解的更多相关文章
- Dom探索之基础详解
认识DOM DOM级别 注::DOM 0级标准实际并不存在,只是历史坐标系的一个参照点而已,具体的说,它指IE4.0和Netscape Navigator4.0最初支持的DHTML. 节点类型 注:1 ...
- Android中Canvas绘图基础详解(附源码下载) (转)
Android中Canvas绘图基础详解(附源码下载) 原文链接 http://blog.csdn.net/iispring/article/details/49770651 AndroidCa ...
- javaScript基础详解(1)
javaScript基础详解 首先讲javaScript的摆放位置:<script> 与 </script> 可以放在head和body之间,也可以body中或者head中 J ...
- Python学习一:序列基础详解
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7858473.html 邮箱:moyi@moyib ...
- Python学习二:词典基础详解
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...
- 深入浅出DOM基础——《DOM探索之基础详解篇》学习笔记
来源于:https://github.com/jawil/blog/issues/9 之前通过深入学习DOM的相关知识,看了慕课网DOM探索之基础详解篇这个视频(在最近看第三遍的时候,准备记录一点东西 ...
- 三剑客基础详解(grep、sed、awk)
目录 三剑客基础详解 三剑客之grep详解 1.通配符 2.基础正则 3.grep 讲解 4.拓展正则 5.POSIX字符类 三剑客之sed讲解 1.sed的执行流程 2.语法格式 三剑客之Awk 1 ...
- java继承基础详解
java继承基础详解 继承是一种由已存在的类型创建一个或多个子类的机制,即在现有类的基础上构建子类. 在java中使用关键字extends表示继承关系. 基本语法结构: 访问控制符 class 子类名 ...
- java封装基础详解
java封装基础详解 java的封装性即是信息隐藏,把对象的属性和行为结合成一个相同的独立单体,并尽可能地隐藏对象的内部细节. 封装的特性是对属性来讲的. 封装的目标就是要实现软件部件的"高 ...
- Java :内部类基础详解
可以将一个类的定义放在另一个类的定义内部,这就是内部类. 第一次见面 内部类我们从外面看是非常容易理解的,无非就是在一个类的内部在定义一个类. public class OuterClass { pr ...
随机推荐
- robot-framework 利用evaluate关键字生成随机数
robot-framework 利用evaluate关键字生成随机数 最近用RF(robot-framework简称)操作MangoDB,需要直接将数据写到数据库里,又不想每次写的数据完全相同,就想到 ...
- C++学习 之 指针及动态内存分配(笔记)
1. 指针 1.1 指针的含义: 简单来说,指针是存储内存地址的变量.当我们声明了一个指针变量后,使用该指针时系统会根据指针内的地址索引内存块,读取内存内的值.指针因为是用来存地址的,所以一般固定长度 ...
- MapReduce框架中的Shuffle机制
Shuffle是map和reduce中间的数据调度过程,包括:缓存.分区.排序等. Shuffle数据调度过程: map task处理hdfs文件,调用map()方法,map task的collect ...
- Http option 请求是怎么回事
在前后台分离的项目中,经常会遇到浏览器想服务端发送一个post/patch请求,实际上产生了两个请求,一个是Option,另一个才是真实的Post/Patch请求, 而get请求则不会产生Option ...
- golang(3):strings和strconv使用 & 时间和日期类型 & 指针类型 & 流程控制 & 函数
strings和strconv使用 . strings.HasPrefix(s string, prefix string) bool: // 判断字符串s是否以prefix开头 . . string ...
- MySQL数据库基础-JAVA
数据库 MySQL初步 MySQL基础认知 (Oracle真的是走哪祸害到哪23333) Java多用MySQL和Oracle SQLServer也收费,但是还行,比Oracle便宜,一个差不多3w多 ...
- axios+FormData文件上传
axios+FormData文件上传 原理:FormData上传 创建一个FormData对象,将得到的文件流对象放在FormData内,然后使用axios上传 注意: 1.请求头设置 headers ...
- 创建全文索引----SQLserver
1.启动 Microsoft Search 服务 开始菜单-->SQL程序组-->服务管理器-->下拉筐-->Microsoft Search 服务-->启动它. 2. ...
- this全面解析<转>
先搞明白一个很重要的概念 —— this的值是在执行的时候才能确认,定义的时候不能确认! 为什么呢 —— 因为this是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候. ...
- Vue基础组件
本文章仅用作于个人学习笔记(蓝后我就可以乱写啦)复制代码 一.组件化的优点当TodoList的todo item越来越多的时候,我们应该把它拆分成一个组件进行开发,维护.组件的出现,就是为了拆分Vue ...