POJ3207,2-sat问题

这也是一道经典的2-sat问题,难在怎样建图。
首先我们需要像普通的2-sat问题一样寻找对立的条件。每条边可以在圆内,也可以在圆外,所以可以把每条边当作一个点p,若在圆内,则为p,若在圆外,则为p’。对于给定的m组数据中,若边x与边y在同一侧要相交的话,就建边<x,y’>,<y,x’>,<y’,x>,<x’,y>,接下来就是判断,看是否矛盾.
至于怎样判断两组数据的边如果连在同一侧是否相交,可以看下面的图进行理解(顺时针点的序号依次增大):
在这里插入图片描述
在这里插入图片描述

所以判断相交的条件为:
a[i]<a[j]&&a[j]<b[i]&&b[i]<b[j]或者a[j]<a[i]&&a[i]<b[j]&&b[j]<b[i]
代码如下:

/*************************************************************************
	> File Name: main.cpp
	> Author:Eagles 
	> Mail:None 
	> Created Time: 2018年09月22日 星期六 09时41分24秒
	> Description:POJ 3207 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
#define N 2000
struct node
{
    int to;
    int nex;
}E[N*N];

struct emm
{
    int scc,low,dfn;
    bool is_in;
    void clear()
    {
        scc=low=dfn=-1;
        is_in=false;
    }
}dot[N];

int head[N];
int a[N],b[N];
int n,m,cnt,dep,col;

void addEdge(int a, int b)
{
    E[cnt].to=b;
    E[cnt].nex=head[a];
    head[a]=cnt++;
}

stack<int>s;

void init()
{
    memset(head,-1,sizeof(head));
    cnt=dep=col=0;

    for (int i=0; i<N; i++)
        dot[i].clear();

    while (!s.empty())
        s.pop();

    for (int i=0; i<m; i++)
    {
        int c,d;
        
        scanf("%d%d",&c,&d);
        
        if (c>d)
            swap(c,d);

        a[i]=c;
        b[i]=d;
    }
}

void tarjan(int u)
{
    s.push(u);
    dot[u].is_in=true;
    dot[u].low=dot[u].dfn=++dep;

    for (int i=head[u]; i!=-1; i=E[i].nex)
    {
        int v=E[i].to;

        if (dot[v].dfn==-1)
        {
            tarjan(v);
            dot[u].low=min(dot[u].low,dot[v].low);
        }
        else if (dot[v].is_in)
            dot[u].low=min(dot[v].dfn,dot[u].low);
    }

    if (dot[u].low == dot[u].dfn)
    {
        ++col;

        int v=s.top();
        s.pop();

        while (v != u)
        {
            dot[v].is_in=false;
            dot[v].scc=col;
            v=s.top();
            s.pop();
        }

        dot[v].scc=col;
        dot[v].is_in=false;
    }
}

bool check(int i, int j)
{
    return (a[i]<a[j]&&a[j]<b[i]&&b[i]<b[j])||(a[j]<a[i]&&a[i]<b[j]&&b[j]<b[i]);
}


bool solve()
{
    for (int i=0; i<m; i++)
    {
        for (int j=i+1; j<m; j++)
        {
            if (check(i,j))
            {
                addEdge(i,j+m);
                addEdge(i+m,j);
                addEdge(j,i+m);
                addEdge(j+m,i);
            }
        }
    }

    for (int i=0; i<2*m; i++)
        if (dot[i].dfn==-1)
            tarjan(i);

    for (int i=0; i<m; i++)
        if (dot[i].scc == dot[i+m].scc)
            return false;

    return true;
}

int main()
{
    while (~scanf("%d%d",&n,&m))
    {
        init();
        if (solve())
            printf("panda is telling the truth...\n");
        else
            printf("the evil panda is lying again\n");
    }
    return 0;
}

发布了45 篇原创文章 · 获赞 2 · 访问量 3080

猜你喜欢

转载自blog.csdn.net/wysiwygo/article/details/82810331
今日推荐