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

题目链接:

点击打开链接

题目大意:

给出一个圆,圆上有一些点,他们之间存在一些边,既可以通过园内相连,也可以通过圆外相连,这些线不相交,问这种情况存在吗?

题目分析:

一条线既可以放在圆外,也可以放在圆内,那么就是2-sat的两种状态,如果某两条边的交叉,也就是某条边的左端点在另一条边的左右端点之间的时候,那么这两条线段就必须放在圆的不同侧,所以就要有关系:假设这两条直线为l1,l2,那么l1在圆内,l1一定在圆外,l2在圆外,l1一定在圆内,l2在圆内,那么l1一定在圆外,l2在圆外,那么l1一定在圆内。然后利用2-sat判断是否有解即可

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <stack>
#define MAX 1007

using namespace std;

typedef pair<int,int> PII;

int mark[MAX],dfn[MAX],low[MAX],belong[MAX],times,cnt;
vector<int> e[MAX];
stack<int> s;

PII p[MAX];

void tarjan ( int u )
{
    dfn[u] = low[u] = ++times;
    mark[u] = 1;
    s.push ( u );
    int len = e[u].size();
    for ( int i = 0 ; i < len ; i++ )
    {
        int v = e[u][i];
        if ( !mark[v] )
        {
            tarjan ( v );
            low[u] = min ( low[u] , low[v] );
        }
        if ( mark[v] == 1 )
            low[u] = min ( low[u] , dfn[v] );
    }
    if ( dfn[u] == low[u] )
    {
        int temp;
        do
        {
            temp = s.top();
            belong[temp] = cnt;
            mark[temp] = 2;
            s.pop();
        }while ( temp != u );
        cnt++;
    }
}

void init ( )
{
    memset ( mark , 0 , sizeof ( mark ));
    for ( int i = 0 ; i < MAX ; i++ )
        e[i].clear();
    while ( !s.empty()) s.pop();
    times = cnt = 0;
}

int n,m;


int main ( )
{
    int u,v;
    while ( ~scanf ( "%d%d" , &n , &m ) )
    {
        init ( );
        for ( int i = 0 ; i < m ; i++ )
        {
            scanf ( "%d%d" , &p[i].first , &p[i].second );
            if ( p[i].first > p[i].second )
                swap ( p[i].first , p[i].second );
        }
        sort ( p , p+m );
        for ( int i = 0 ; i < m ; i++ )
            for ( int j = i+1 ; j < m ; j++ )
            {
                if ( p[i].first < p[j].first &&
                     p[j].second > p[i].second &&
                     p[i].second > p[j].first )
                {
                    e[i*2].push_back ( j*2+1 );
                    e[j*2].push_back ( i*2+1 );
                    e[i*2+1].push_back ( j*2 );
                    e[j*2+1].push_back ( i*2 );
                }
            }

        for ( int i = 0 ; i < 2*m ; i++ )
            if ( !mark[i] ) tarjan ( i );

        bool flag = true;
        for ( int i = 0 ; i < m ; i++ )
            if ( belong[i<<1] == belong[i<<1|1] )
                flag = false;

        if ( flag )
            puts ( "panda is telling the truth...");
        else puts ("the evil panda is lying again");
    }
}


你可能感兴趣的:(图论,2-sat)