zoukankan      html  css  js  c++  java
  • poj 3207 Ikki's Story IV

    题目链接: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...
    ");
            else
                printf("the evil panda is lying again
    ");
        }
        return 0;
    }
  • 相关阅读:
    PVE6.3去订阅
    帝国CMS灵动标签当天更新的日期显示红色其他颜色变成灰色
    灵动标签实现循环子栏目数据——实现 循环子栏目数据标签 (listsonclass)的效果
    帝国cms灵动标签实现循环子栏目数据
    帝国cms常用灵动标签
    51nod1847 奇怪的数学题
    CTS2019 氪金手游
    CTS2019 重复
    UR #5 怎样跑得更快
    AGC034 F
  • 原文地址:https://www.cnblogs.com/tallisHe/p/4681880.html
Copyright © 2011-2022 走看看