2-SAT问题

来源:互联网 发布:java 汉字验证码 编辑:程序博客网 时间:2024/05/29 03:55

2-SAT问题

图论·2-SAT

部分内容来自
http://www.cnblogs.com/kuangbin/archive/2012/10/05/2712429.html

描述:

现有一个由N个布尔值组成的序列A,给出一些限制关系,比如A[x] AND A[y]=0、A[x] OR A[y] OR A[z]=1等,要确定A[0..N-1]的值,使得其满足所有限制关系。这个称为SAT问题,特别的,若每种限制关系中最多只对两个元素进行限制,则称为2-SAT问题。

由于在2-SAT问题中,最多只对两个元素进行限制,所以可能的限制关系共有11种:
A[x]
NOT A[x]
A[x] AND A[y]
A[x] AND NOT A[y]
A[x] OR A[y]
A[x] OR NOT A[y]
NOT (A[x] AND A[y])
NOT (A[x] OR A[y])
A[x] XOR A[y]
NOT (A[x] XOR A[y])
A[x] XOR NOT A[y]
进一步,A[x] AND A[y]相当于(A[x]) AND (A[y])(也就是可以拆分成A[x]与A[y]两个限制关系),NOT(A[x] OR A[y])相当于NOT A[x] AND NOT A[y](也就是可以拆分成NOT A[x]与NOT A[y]两个限制关系)。因此,可能的限制关系最多只有9种。

在实际问题中,2-SAT问题在大多数时候表现成以下形式:有N对物品,每对物品中必须选取一个,也只能选取一个,并且它们之间存在某些限制关系(如某两个物品不能都选,某两个物品不能都不选,某两个物品必须且只能选一个,某个物品必选)等,这时,可以将每对物品当成一个布尔值(选取第一个物品相当于0,选取第二个相当于1),如果所有的限制关系最多只对两个物品进行限制,则它们都可以转化成9种基本限制关系,从而转化为2-SAT模型。

建模:

其实2-SAT问题的建模是和实际问题非常相似的。
建立一个2N阶的有向图,其中的点分为N对,每对点表示布尔序列A的一个元素的0、1取值(以下将代表A[i]的0取值的点称为i,代表A[i]的1取值的点称为i’)。显然每对点必须且只能选取一个。然后,图中的边具有特定含义。若图中存在边

求解:

O(m)算法:判断是否可行,求一组可行解

建好图后跑强连通分量,如果x0和x1在同一个强连通分量里则无解,如果x1所在的强连通分量的拓扑序在x2所在的强连通分量之后,则x为真;否则为假。
(拓扑序哪个大哪个是对的)
为了方便拓扑序,求强连通分量的时候建议使用两遍dfs直接求出拓扑序的方法。

O(m)算法,判断是否可行,求字典序最小的解

x是一个还没有考虑到的编号最小变量,为了字典序最小,先假设它为否,标记x0,从x0开始dfs,标记沿途进过的点,如果发现矛盾,即一个点的0和1都被标记了,则说明x为否不行,把沿途的标记清除。
标记x1,重复上述过程。
如果发现x0 x1都不行,则原问题无解。
最后如果x0被标记了,x为否;x1被标记了,x为真。

Code:

bool dfs(int x){    if(mark[x^1]) return false;    //x^1 必须从0开始编号     if(mark[x]) return true;    mark[x]=true;     S[++S[0]]=x;    for(int i=head[x];i;i=e[i].next){        if(!dfs(e[i].to)) return false;    }    return true;}bool solve(){    for(int i=0;i<n*2;i+=2){        if(!mark[i] && !mark[i+1]){            S[0]=0;            if(!dfs(i)){                while(S[0]) mark[S[0]--]=false;                if(!dfs(i+1)) return false;            }        }    }    return true;}
原创粉丝点击