poj 3207 Ikki's Story IV - Panda's Trick(2-SAT)

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

思路分析:该问题给出N个点,并给出M条连接这些点的线,需要判断是否这些线不会相交;

(1)假设两条线A的端点按照圆圈的顺时针方向依次为A0,A1,同理线B为B0, B1,则可以知道当 A0 < B0 < A1 < B1 或者 B0 < A0 < B1 < A1时线A与B如果同时在内侧或者外侧,则线A与B必定相交;

(2)将M条线视为图中的M个布尔变量,每条线或者在内侧或者在外侧,如果线段A与B在同一侧并定相交,则可以得到等价式:线A在内侧—>线B在外侧,线A在外侧—>线B在内侧,线B在内侧—>线A在外侧,线B在外侧—>线A在内侧;

 

代码如下:

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

const int MAX_N = 5000 + 10;
int e[MAX_N][MAX_N];

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 a = 2 * x;
        int b = 2 * y;
        G[a].push_back(b ^ 1);
        G[a ^ 1].push_back(b);
        G[b].push_back(a ^ 1);
        G[b ^ 1].push_back(a);
    }

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

inline bool Judge(int x, int y)
{
    if ((e[x][0] < e[y][0]) && (e[y][0] < e[x][1])
        && (e[x][1] < e[y][1]))
        return true;
    if ((e[y][0] < e[x][0]) && (e[x][0] < e[y][1])
        && (e[y][1] < e[x][1]))
        return true;
    return false;
}

inline void Swap(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

TwoSAT sat;

int main()
{
    int n, m;

    while (scanf("%d %d", &n, &m) != EOF)
    {
        memset(e, 0, sizeof(e));
        sat.Init(m);
        for (int i = 0; i < m; ++i)
        {
            scanf("%d %d", &e[i][0], &e[i][1]);
            if (e[i][0] > e[i][1])
                Swap(e[i][0], e[i][1]);
        }
        for (int i = 0; i < m; ++i)
        {
            for (int j = i + 1; j < m; ++j)
            {
                if (Judge(i, j))
                    sat.AddClause(i, j);
            }
        }
        bool ok = sat.Solve();
        if (ok)
            printf("panda is telling the truth...\n");
        else
            printf("the evil panda is lying again\n");
    }
    return 0;
}
posted @ 2015-07-28 09:32  Leptus  阅读(173)  评论(0编辑  收藏  举报