poj 3678 Katu Puzzle(2-SAT)

题目链接:http://poj.org/problem?id=3678

思路分析:该问题要求判断是否能给定每一个布尔变量一个值,使布尔变量满足某些逻辑条件;

需要根据逻辑条件来进行点与点的连接:假设两个变量为a与b,2 * a表示a的值为0的点,2 * a + 1表示a的值为1的点,则可以根据逻辑条件给出给出连接的边;

a AND b == 1 =》 a与b的值必定为1,所以2 * a –> 2 * a + 1, 2 * b –> 2 * b + 1,表示a,b必定为1;

如果a或者b为0,则2 * a 与 2 * a + 1联通,则矛盾,错误;

a AND b == 0 =>  2 * a + 1 –> 2 * b,  2 * b + 1 –> 2 * a;

a OR b == 1   =>  2 * a –> 2 * b + 1, 2 * b –> 2 * a + 1;

a OR b == 0   =>  a与b的值必定为0,所以 2 * a + 1 –> 2 * a, 2 * b + 1 –> 2 * b;

a XOR b == 1 =>  a与b的值不同,2 * a –> 2 * b + 1, 2 * a + 1 -> 2 * b, 2 * b + 1 –> 2 * a, 2 * b –> 2 * a + 1;

a XOR b == 1 =>  a与b的值相同,2 * a –> 2 * b, 2 * b –> 2 * a, 2 * a + 1 –> 2 * b + 1, 2 * b + 1 –> 2 * a + 1;

代码如下:

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>

using namespace std;
const int MAX_N = 1000 + 10;

struct TwoSAT {
    int n;
    vector<int> G[2 * MAX_N];
    bool mark[2 * MAX_N];
    int S[2 * MAX_N], c;

    void Init(int n)
    {
        this->n = n;
        for (int i = 0; i <= 2 * n; ++i)
            G[i].clear();
        memset(mark, 0, sizeof(mark));
    }

    void AddClause(int x, int y, int z, char *op)
    {
        int a = 2 * x;
        int b = 2 * y;
        int c = z;

        if (op[0] == 'A')
        {
            if (c == 1)
            {
                G[a].push_back(a ^ 1);
                G[b].push_back(b ^ 1);
            }
            else
            {
                G[a ^ 1].push_back(b);
                G[b ^ 1].push_back(a);
            }
        } 
        else if (op[0] == 'O')
        {
            if (c == 1)
            {
                G[a].push_back(b ^ 1);
                G[b].push_back(a ^ 1);
            } else
            {
                G[a ^ 1].push_back(a);
                G[b ^ 1].push_back(b);
            }
        } else
        {
            if (c == 1)
            {
                G[a].push_back(b ^ 1);
                G[a ^ 1].push_back(b);
                G[b ^ 1].push_back(a);
                G[b].push_back(a ^ 1);
            } else
            {
                G[a].push_back(b);
                G[b].push_back(a);
                G[a ^ 1].push_back(b ^ 1);
                G[b ^ 1].push_back(a ^ 1);
            }
        }
    }

    bool Dfs(int x)
    {
        if (mark[x ^ 1])  return false;
        if (mark[x])      return true;
        mark[x] = true;
        S[c++] = x;

        for (int i = 0; i < G[x].size(); ++i)
        {
            if (!Dfs(G[x][i]))
                return false;
        }
        return true;
    }

    bool Solve()
    {
        for (int i = 0; i < 2 * n; i += 2)
        {
            if (!mark[i] && !mark[i + 1])
            {
                c = 0;
                if (!Dfs(i))
                {
                    while (c > 0) mark[S[--c]] = false;
                    if (!Dfs(i + 1))
                        return false;
                }
            }
        }
        return true;
    }
};

TwoSAT sat;

int main()
{
    int n, m;
    int a, b, c;
    char op[20];

    while (scanf("%d %d", &n, &m) != EOF)
    {
        sat.Init(n);
        for (int i = 0; i < m; ++i)
        {
            scanf("%d %d %d", &a, &b, &c);
            scanf("%s", op);
            sat.AddClause(a, b, c, op);
        }
        bool ok = sat.Solve();
        if (ok)
            printf("YES
");
        else
            printf("NO
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/tallisHe/p/4682096.html