这道题感觉最难的是想到他是一个2-sat,即使我是按2-sat题目去找的……
想了很久,还是觉得像贪心,但是贪心之后就不太好做了,以下是参考别人的代码写的,
翻了好多代码,都不太理解,最后感觉这个感觉比较好理解吧,,但忘了是谁的blog里面的了
先不写明出处了先
/*
题意是:在一个有0,1,2,。。。n-1 个点组成的圆中,只能从圆里面和外面画线,
问你能否将m条边连起来,并且不能相交。
我的想法是:对于每条边要么从圆里面走,要么从圆外面走。那么,我们这样定义i
表示从里面走,i+n表示从外面走。然后我们遍历所有的两两边,如果他们交错了,
那么他们之间就有这样的关系:i从里面走,那么j就得走外面,i从外面走,那么j就
得走里面,反之亦然,即:
i->j+n i+n->j j->i+n j+n->i
理解:把点当边,把边当点
2011-7-13
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define nMax 1005
#define mMax 505
using namespace std;
int dfn[nMax], low[nMax], stack[nMax], belong[nMax],a[mMax], b[mMax];
int top, cnt, n, m, ans;
bool instack[nMax];
vector<int> tree[nMax];
void init()
{
for(int i=0; i<n*2; i++)
{
tree[i].clear();
}
}
void BuildGraph()
{
for(int i=0; i<m; i++)
{
scanf("%d%d", &a[i], &b[i]);
if(a[i]>b[i]) swap(a[i], b[i]);
}
for(int i=0; i<m; i++)
{
for(int j=i+1; j<m; j++)
{
if((a[i]<a[j] && b[i]<b[j] && a[j]<b[i]) || (a[i]>a[j] && b[i]>b[j] && a[i]<b[j]))
{
tree[2*i].push_back(2*j+1);
tree[2*j+1].push_back(2*i);
tree[2*j].push_back(2*i+1);
tree[2*i+1].push_back(2*j);
}
}
}
}
void dfs(int i)
{
int j;
dfn[i]=low[i]=++ans;
instack[i]=true;
stack[++top]=i;
for(int k=0; k<tree[i].size(); k++)
{
j=tree[i][k];
if(!dfn[j])
{
dfs(j);
if(low[j]<low[i])
low[i]=low[j];
}
else if(instack[j] && dfn[j]<low[i])
low[i]=dfn[j];
}
if(dfn[i]==low[i])
{
cnt++;
do
{
j=stack[top--];
instack[j]=0;
belong[j]=cnt;
}while(j!=i);
}
}
void Tarjan()
{
top=cnt=ans=0;
memset(dfn, 0, sizeof(dfn));
for(int i=0; i<2*m; i++)
if(!dfn[i])
dfs(i);
}
bool Judge()
{
for(int i=0; i<2*m; i+=2)
if(belong[i]==belong[i+1])
return 0;
return 1;
}
int main()
{
scanf("%d%d", &n, &m);
init();
BuildGraph();
Tarjan();
if(Judge()) puts("panda is telling the truth...");
else puts("the evil panda is lying again");
return 0;
}