zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    百度面试题
    京东2014年招聘会成都站笔试经历
    把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,不能申请额外的空间
    POJ 2234 Matches Game
    POJ 3903 Stock Exchange
    POJ 2853 Sequence Sum Possibilities
    POJ 3519 Minimal Backgammon
    POJ 2096 Collecting Bugs
    POJ 3071 Football
    HDU 1175 连连看
  • 原文地址:https://www.cnblogs.com/tallisHe/p/4682096.html
Copyright © 2011-2022 走看看