POJ - 3207 Ikki‘s Story IV - Panda‘s Trick

Posted 吃花椒的妙酱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ - 3207 Ikki‘s Story IV - Panda‘s Trick相关的知识,希望对你有一定的参考价值。

传送门

题目大意:一个圆上n个点,按顺时针排布,对定m组连线,连线可以在圆内或者圆外,问是否存在方法,使得任意两条线段不相交。

画一下图可以发现,当a < b < c < d时,两条线在圆内或者圆外相交

我们研究的对象是每条线段,线段无非在圆内或圆外,转化成2sat问题。

我们将所有线段编号,枚举判断两两线段是否满足相交的条件,若满足,就去建图,举个例子。

如上图,若ac在圆内,则bd必在圆外,若ac在圆外,则bd必在圆内,这样对于满足相交的两个线段就可以去连两条边。

设两条线段编号为x,y共n条,x,y表示线段在圆内,x+n,y+n表示线段在圆外,如果两者满足相交条件,则有有向边,x->y+n,x+n->y,y->x+n,y+n->x

后面就是套路了,看一下圆内圆外的同一条线段col[i] == col[i+n]?是否在同一强连通块里,是的话说明矛盾,反之成立

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pb push_back
#define IOS ios::sync_with_stdio(false)
#define int long long
#define inf 0x3f3f3f3f
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define ls p<<1
#define rs p<<1|1
#define endl "\\n"
#define sf scanf
typedef long long ll;
const int N = 1000 + 10;//500条边,
int n, m;
int sta[N],low[N],dfn[N],col[N],tot,top,ti;
bool pd[N];
vector <int> G[N];
void tarjan(int x)
{
    sta[++top] = x;
    pd[x] = 1;
    dfn[x] = low[x] = ++ti;
    for (int i = 0; i < G[x].size(); i++)
    {
        int y = G[x][i];
        if (!dfn[y])
        {
            tarjan(y);
            low[x] = min(low[x], low[y]);
        }
        else if (pd[y])
        {
            low[x] = min(low[x], low[y]);
        }
    }
    if (dfn[x] == low[x])
    {
        tot++;
        while (sta[top + 1] != x)
        {
            col[sta[top]] = tot;
            pd[sta[top--]] = 0;
        }
    }
}
struct ty
{
    int x, y;
}edge[N];
bool min4(int a, int b, int c, int d)
{
    if (a < b && b < c && c < d) return true;
    return false;
}
bool check(int i, int j)//相交
{
    int a = edge[i].x;
    int b = edge[i].y;
    int c = edge[j].x;
    int d = edge[j].y;
    if (min4(a, c, b, d)) return true;
    if (min4(c, a, d, b)) return true;
    return false;
}
signed main()
{
    ///!!!
    //freopen("data.txt","r",stdin);
    //!!!
    IOS;
    cin >> n >> m;
    _for(i, 1, m)
    {
        int x, y; cin >> x >> y;
        if (x > y) swap(x, y);
        edge[i] = { x,y };
    }
    
    _for(i, 1, m)
    {
        _for(j, i + 1, m)
        {
            //如果相交就建图
            //边的编号+n表示连在圆外
            if (check(i, j))
            {
                G[i].push_back(j + m);
                G[j].push_back(i + m);
                G[i + m].pb(j);
                G[j + m].pb(i);
            }
        }
    }
    _for(i, 1, 2 * m) if (!dfn[i]) tarjan(i);
    _for(i, 1, m)
    {
        //如果一条边在一个连通块里->同时出现在圆外和圆内
        if (col[i] == col[i + m])
        {
            cout << "the evil panda is lying again";
            return 0;
        }
    }
    cout << "panda is telling the truth...";
    return 0;
}

 

以上是关于POJ - 3207 Ikki‘s Story IV - Panda‘s Trick的主要内容,如果未能解决你的问题,请参考以下文章

poj3207 Ikki's Story IV - Panda's Trick

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

[2-SAT] poj 3207 Ikki&#39;s Story IV - Panda&#39;s Trick

POJ 3207 Ikki's Story IV - Panda's Trick

POJ 3207 Ikki&#39;s Story IV - Panda&#39;s Trick(2-sat)

POJ3207 Ikki's Story IV - Panda's Trick