---------------------------------------------------------------------------------------------------------以下转载自http://cainiao2hao.blogcn.com/articles/poj3207.html
平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,使这些边都不相交。
解题报告:题意可能刚开始不是很好理解,比如1 5连边,2,6连边,由于点是顺序排列的,一画图就可以发现,这两条边必须一个从圆外面连,一个从内部连,否则就会相交。如果再加入3 7这条边,那么就必须相交了。
这样,就可以转化成标准的2-sta问题:
1:每个边看成2个点:分别表示在内部连接和在外部连接,只能选择一个。计作点i和点i'
2:如果两条边i和j必须一个画在内部,一个画在外部(一个简单判断就可以)
那么连边:
i->j’, 表示i画内部的话,j只能画外部,即j’
j->i’,同理
i’->j,同理
j’->i,同理
然后就是2-sat算法了,tarjan一下,如果有i和i'同属于一个强联通,返回false,否则就成立。
------------------------------------------------------------------------------------------------------------------------
然后是我的代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define MAXN 1005
#define MAXM 2000005
#define INF 1000000000
using namespace std;
int n, m, e, head[MAXN];
int dfn[MAXN], low[MAXN], index, instack[MAXN], scc;
int top, st[MAXN], fa[MAXN];
int x[MAXN], y[MAXN];
struct Edge
{
int v, next;
}edge[MAXM];
void init()
{
e = index = scc = top = 0;
memset(dfn, 0, sizeof(dfn));
memset(instack, 0, sizeof(instack));
memset(head, -1, sizeof(head));
}
void insert(int x, int y)
{
edge[e].v = y;
edge[e].next = head[x];
head[x] = e++;
}
void tarjan(int u)
{
int v;
instack[u] = 1;
st[++top] = u;
dfn[u] = low[u] = ++index;
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u])
{
scc++;
do
{
v = st[top--];
instack[v] = 0;
fa[v] = scc;
}while(v != u);
}
}
void build()
{
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &x[i], &y[i]);
x[i]++; y[i]++;
if(x[i] > y[i]) swap(x[i], y[i]);
}
for(int i = 1; i <= m; i++)
for(int j = i + 1; j <= m; j++)
if((x[i] <= x[j] && y[i] >= x[j] && y[i] <= y[j]) || (x[i] >= x[j] && x[i] <= y[j] && y[i] >= y[j]))
{
insert(i, j + m);
insert(j, i + m);
insert(i + m, j);
insert(j + m, i);
}
n = 2 * m;
}
bool check()
{
for(int i = 1; i <= m; i++)
if(fa[i] == fa[i + m]) return false;
return true;
}
void solve()
{
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
if(check()) printf("panda is telling the truth...\n");
else printf("the evil panda is lying again\n");
}
int main()
{
scanf("%d%d", &n, &m);
init();
build();
solve();
return 0;
}