zoukankan      html  css  js  c++  java
  • 闲谈2-sat问题

    问题简介

    在计算机科学中,布尔可满足性问题(有时称为命题可满足性问题,缩写为SATISFIABILITY或SAT)是确定是否存在满足给定布尔公式的解释的问题。换句话说,它询问给定布尔公式的变量是否可以一致地用值TRUE或FALSE替换,公式计算结果为TRUE。如果是这种情况,公式称为可满足。另一方面,如果不存在这样的赋值,则对于所有可能的变量赋值,公式表示的函数为FALSE,并且公式不可满足。例如,公式“a AND NOT b”是可以满足的,因为可以找到值a = TRUE且b = FALSE,这使得(a AND NOT b)= TRUE。相反,“a AND NOT a”是不可满足的。——百度百科

    在每个限制中牵扯到的最多的元素假设是(k),我们就称为(k-sat)问题。可以证明当(k ge 3)时为(np)完全问题。下面只讨论(k=2)的情况。

    引入

    从一个最简单的(2-sat)问题开始今天的讨论

    有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?——hdu3062

    对于每对夫妻,我们可以将丈夫去看作(1),妻子去看作(0)。要求给每对夫妻确定一个值,使得满足这(m)个限制。

    这就是最简单的(2-sat)模型。

    构图

    先观察这些限制,假设A中的丈夫不能和B中的妻子一起去(???)。那么也就是说,A中的丈夫只能和B中的丈夫一起去。也就是说,如果A中的丈夫去,那么B中的丈夫也必须去。同理,如果B中的妻子去,那么A中的妻子也必须去
    我们就从A中的丈夫向B中的丈夫连一条边,从B中的妻子向A中的妻子连一条边,表示这些"必须"的条件。

    显然我们就可以得到这样一个结论:如果一个点被选了,那么这个点所能到达的所有点也必须被选择。如果一个点没选,那么所有可以到达这个点的点都不能选。出现矛盾当且仅当某对夫妻的丈夫和妻子都必须去。

    算法

    暴力解法

    我们枚举每一个人选或者不选,然后去查看是否会出现矛盾。
    如果一对夫妻中两个人不论选择谁都会出现矛盾。那么问题必定无解。

    优化

    继续推一些结论。
    对于同一个强连通分量里的点,如果选择其中一个,那么这个强连通分量中的点必须全部选择。这样我们可以先(tarjan)缩点。如果一对夫妻出现在了同一个强连通分量里面肯定无解。否则一定有解。
    找可行解可以先拓扑排序一下,然后自底向上的顺序推导。

    证明

    观察我们的构图方式可以发现构出来的图有对称性
    啥是对称性??

    如图。我们观察其中的一组点,比如(c)

    发现可以到达(c_0)的点是(a_0),(c_0)可以到达的点是(d_0),而可以到达(c_1)的点是(d_1),(c_1)可以到达的点是(a_1)。刚好对称。也就是说我们只要保证(c_0)可以到达的不会矛盾,那么就可以保证可以到达(c_1)的点不会矛盾。我们如果选择了(c_0),那么就一定选择(d_0),这时把(c_1)(d_1)都删去。按照这种思路,我们每次找到一个未确定的点(x),使得(x)到达的点中没有(x')(即x的对立点)。
    这样我们一定可以找到一组解。而无解的情况也就是找不到这种点的时候。即一对点存在于同一个强连通分量中。
    然后思考求解的过程,因为要使得“(x)到达的点中没有(x')(即x的对立点)。”
    所以可以拓扑排序。然后就自底向上的找答案。
    有一种更加简单的找可行解的方法。

    注意到(Tarjan)算法的本质是一次(dfs),他在回溯时会优先取出有向图"底部"的(scc)进行标记。故(Tarjan)算法得到的(scc)编号本身就已经满足缩点后的有向无环图中"自底向上"的拓扑序。——《算法竞赛进阶指南》

    得出结论:直接比较缩点之后编号的大小就可以得出答案,较小的为1,较大的为0。

    资料

    我讲的不好??
    没关系,再看些资料吧。
    https://blog.csdn.net/qq_24451605/article/details/47126143
    由对称性解2-sat问题

    代码

    /*
    * @Author: wxyww
    * @Date:   2019-04-28 18:50:21
    * @Last Modified time: 2019-04-28 19:59:02
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 2010;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    struct node{
    	int v,nxt;
    }e[1000000];
    int n,m,ejs,head[N];
    void add(int u,int v) {
    	e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;
    }
    int vis[N],tot,dfn[N],low[N],sta[N],coljs,top,col[N];
    void tarjan(int u) {
        dfn[u] = low[u] = ++tot;
        sta[++top] = u;vis[u] = 1;
        for(int i = head[u];i;i = e[i].nxt) {
            int v = e[i].v;
            if(!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u],low[v]);
            }
            else if(vis[v]) low[u] = min(low[u],low[v]);
        }
        if(low[u] == dfn[u]) {
            ++coljs;
            do {
                int x = sta[top--];
                col[x] = coljs;
                vis[x] = 0;
            }while(sta[top + 1] != u);
        }
    }
    int main() {	
    	while(~scanf("%d%d",&n,&m)) {
       memset(head,0,sizeof(head));
       ejs = 0;
       coljs = 0;
       memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
       tot = 0;top = 0;
    	
    	for(int i = 1;i <= m;++i) {
    		int x = read() + 1,y = read() + 1;
    		int c1 = read(),c2 = read();
    		if(c1) {
    			if(c2) add(x + n, y),add(y + n,x);
    			else add(x + n,y + n),add(y,x);
    		}
    		else {
    			if(c2) add(x, y),add(y + n,x + n);
    			else add(x,y + n),add(y,x + n);
    		}
    	}
    
    	for(int i = 1;i <= n + n;++i) if(!dfn[i]) tarjan(i);
    	int bz = 0;
    	for(int i = 1;i <= n;++i) {
    		if(col[i] == col[i + n]) {
    			bz = 1;break;
    		}
    	}
    	puts(bz ? "NO" : "YES");
    }
    	return 0;
    }
    
  • 相关阅读:
    POJ 2723 Get Luffy Out(2-SAT)
    ZOJ 3613 Wormhole Transport
    HDU 4085 Peach Blossom Spring
    NBUT 1221 Intermediary
    NBUT 1223 Friends number
    NBUT 1220 SPY
    NBUT 1218 You are my brother
    PAT 1131. Subway Map (30)
    ZSTU OJ 4273 玩具
    ZSTU OJ 4272 最佳淘汰算法
  • 原文地址:https://www.cnblogs.com/wxyww/p/2-sat.html
Copyright © 2011-2022 走看看