2-SAT适定性问题与逻辑图

2-SAT适定性问题与逻辑图

逻辑图

逻辑图是一种有向图,图中每一个节点代表了一个命题,如果命题 a a a是命题 b b b的充分不必要条件,那么在 a a a b b b之间就存在一条有向边 a → b a \to b ab。如果 a a a b b b互为充要条件,那么 a a a b b b之间存在双向边。

构建逻辑图可以为我们通过图论解决命题之间的关系等问题,例如2-SAT问题。

2-SAT适定性问题

SAT 是适定性(Satisfiability)问题的简称。一般形式为 k - 适定性问题,简称 k-SAT。而当 k > 2 k > 2 k>2 时该问题为 NP 完全的。所以我们只研究 k = 2 k=2 k=2 的情况。

给定一个逻辑表达式:

L = ( a 1 ∨ b 1 ) ∧ ( a 2 ∨ b 2 ) ∧ … ∧ ( a n ∨ b n ) L = (a_1 \vee b_1) \wedge (a_2 \vee b_2) \wedge \ldots \wedge (a_n \vee b_n) L=(a1b1)(a2b2)(anbn)

再给定一组未知布尔变量组 X = ( x 1 , x 2 , x 3 , … , x m ) X = (x_1,x_2,x_3,\ldots,x_m) X=(x1,x2,x3,,xm),其中 a i a_i ai b i b_i bi要么等于 x j x_j xj要么等于 ¬ x j \neg x_j ¬xj

求解是否有可行的 X X X的解集,或者报告无解。上述问题称为2-SAT问题, L L L为2-SAT逻辑表达式。

求解

我们注意到,如果存在条件 ( a i ∨ b i ) (a_i \vee b_i) (aibi),那么有 ¬ a i → b i \neg a_i \to b_i ¬aibi ¬ b i → a i \neg b_i \to a_i ¬biai。我们根据这个关系建立逻辑图。

例如:

L 2 = ( x 2 ∨ ¬ x 1 ) ∧ ( ¬ x 1 ∨ ¬ x 2 ) ∧ ( x 1 ∨ x 3 ) ∧ ( ¬ x 2 ∨ ¬ x 3 ) ∧ ( ¬ x 1 ∨ x 4 ) L 2 = ( x 1 ∨ x 2 ) ∧ ( x 1 ∨ ¬ x 2 ) ∧ ( ¬ x 1 ∨ x 3 ) ∧ ( ¬ x 1 ∨ ¬ x 3 ) L_2 = (x_2 \vee \neg x_1) \wedge (\neg x_1 \vee \neg x_2) \wedge (x_1 \vee x_3) \wedge (\neg x_2 \vee \neg x_3) \wedge (\neg x_1 \vee x_4) \\ L_2 = (x_1 \vee x_2) \wedge (x_1 \vee \neg x_2) \wedge (\neg x_1 \vee x_3) \wedge (\neg x_1 \vee \neg x_3) L2=(x2¬x1)(¬x1¬x2)(x1x3)(¬x2¬x3)(¬x1x4)L2=(x1x2)(x1¬x2)(¬x1x3)(¬x1¬x3)

则有 L 1 L_1 L1逻辑图:

L1

L 2 L_2 L2逻辑图:

L2

其解存在的充要条件为: x i x_i xi ¬ x i \neg x_i ¬xi不在同一个强连通分量中。如果存在 x i x_i xi ¬ x i \neg x_i ¬xi在同一强连通分量,那么这两者不可能同时为 True \text{True} True,故解自然不存在。

L 1 L_1 L1满足这个条件,故 L 1 L_1 L1的解存在。 L 2 L_2 L2不满足,则 L 2 L_2 L2的解不存在。

判断解存不存在之后,我们要构造一个可行解。

我们发现,如果缩点之后的分量图中存在 ¬ x i → x i \neg x_i \to x_i ¬xixi,那么 x i x_i xi一定为 True \text{True} True,反之存在 x i → ¬ x i x_i \to \neg x_i xi¬xi,那么 x i x_i xi一定为 False \text{False} False。那么我们就可以选择 x i x_i xi ¬ x i \neg x_i ¬xi谁的拓扑序靠后,谁的就为 True \text{True} True。这样就能构造出一组可行解。

例题

P4782

#include <bits/stdc++.h>

#define FR freopen("in.txt", "r", stdin)

typedef long long ll;
using namespace std;

int n, m;

#define RS(x) (x <= n ? n + x : x - n)

struct Edge
{
    int nxt;
    int to;
} e[2000005];

int head[2000005];
int tot = 0;

void add(int u, int v)
{
    tot++;
    e[tot].to = v;
    e[tot].nxt = head[u];
    head[u] = tot;
}

int dfn[2000005];
int low[2000005];
bool inStack[2000005];
stack<int> sta;
int ti = 0;

int topo[2000005];
int id = 0;

int val[2000005];

void tarjan(int u)
{
    low[u] = dfn[u] = ++ti;
    inStack[u] = true;
    sta.push(u);
    for (int ne = head[u]; ne; ne = e[ne].nxt)
    {
        int to = e[ne].to;

        if (dfn[to] == 0)
        {
            tarjan(to);
            low[u] = min(low[u], low[to]);
        }
        else if (inStack[to])
        {
            low[u] = min(low[u], dfn[to]);
        }
    }

    if (dfn[u] == low[u])
    {
        id++;
        int curr;
        do
        {
            curr = sta.top();
            sta.pop();
            inStack[curr] = false;
            topo[curr] = id;
        } while (curr != u);
    }
}

int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++)
    {
        int a, b, c, d;
        scanf("%d %d %d %d", &a, &b, &c, &d);
        if (b == 0)
            a = RS(a);
        if (d == 0)
            c = RS(c);
        add(RS(a), c);
        add(RS(c), a);
    }

    for (int i = 1; i <= 2 * n; i++)
    {
        if (dfn[i] == 0)
        {
            tarjan(i);
        }
    }

    for (int i = 1; i <= n; i++)
    {
        if (topo[i] == topo[RS(i)])
        {
            printf("IMPOSSIBLE\n");
            return 0;
        }
        else if (topo[i] > topo[RS(i)])
        {
            val[i] = 0;
        }
        else if (topo[i] < topo[RS(i)])
        {
            val[i] = 1;
        }
    }

    printf("POSSIBLE\n");
    for (int i = 1; i <= n; i++)
    {
        printf("%d ", val[i]);
    }
    return 0;
}

P4171

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值