这也是一道经典的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;
}