码迷,mamicode.com
首页 > 其他好文 > 详细

hdoj 1824 Let's go home(2-SAT)

时间:2015-07-27 22:52:44      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1824

思路分析:该问题为2-SAT问题;需要注意逻辑推理的等价性;

(1)题目第一个条件:每一个队或者队长留下或者其与两名队员同时留下,或者表明只能为两种情况中的一种;假设三人为A,B,C,队长为A,0表示不留下,1表示留下,因为B与C同时留下或者不留下,只要B,C中其中一个没有留下或者留下,则B,C中另一个也同样留下或者不留下,所以可以从该条件中推导出六条等价关系,即A不留下->B,C同时留下,A留下->B,C同时不留下,B留下->C留下,A不留下,B留下->C留下,A不留下,C留下->B留下,A不留西,C不留下->B不留下,A留下;

(2)题目中第二个条件:每一对队员,如果队员A留下,则B必须回家休息,或者B留下,A必须回家休息;则可以推导出两条等价式:A留下->B不留下,B留下->A不留下,注意在这个条件中可以A,B都不留下;

 

代码如下:

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;

const int MAX_N = 2 * 5000 + 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));
    }

    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;
    }

    void AddClause(int x, int y)
    {
        int a = 2 * x;
        int b = 2 * y;
        G[a ^ 1].push_back(b);
        G[b ^ 1].push_back(a);
    }

    void AddClauseTeam(int i, int j, int k)
    {
        int a = 2 * i;
        int b = 2 * j;
        int c = 2 * k;
        G[a].push_back(b ^ 1);
        G[a].push_back(c ^ 1);
        G[b].push_back(a ^ 1);
        G[b].push_back(c);
        G[c].push_back(a ^ 1);
        G[c].push_back(b);
        G[a ^ 1].push_back(b);
        G[a ^ 1].push_back(c);
        G[b ^ 1].push_back(a);
        G[b ^ 1].push_back(c ^ 1);
        G[c ^ 1].push_back(a);
        G[c ^ 1].push_back(b ^ 1);
    }

    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;

    while (scanf("%d %d", &n, &m) != EOF)
    {
        int a, b, c;
        sat.Init(3 * n);
        for (int i = 0; i < n; ++i)
        {
            scanf("%d %d %d", &a, &b, &c);
            sat.AddClauseTeam(a, b, c);
        }
        for (int i = 0; i < m; ++i)
        {
            scanf("%d %d", &a, &b);
            sat.AddClause(a, b);
        }

        bool ok = sat.Solve();
        if (ok)
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}

hdoj 1824 Let's go home(2-SAT)

标签:

原文地址:http://www.cnblogs.com/tallisHe/p/4681259.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!