liympanda, one of Ikki’s friend, likes playing games with Ikki. Today after minesweeping with Ikki and winning so many times, he is tired of such easy games and wants to play another game with Ikki.ios
liympanda has a magic circle and he puts it on a plane, there are n points on its boundary in circular border: 0, 1, 2, …, n − 1. Evil panda claims that he is connecting m pairs of points. To connect two points, liympanda either places the link entirely inside the circle or entirely outside the circle. Now liympanda tells Ikki no two links touch inside/outside the circle, except on the boundary. He wants Ikki to figure out whether this is possible…ide
Despaired at the minesweeping game just played, Ikki is totally at a loss, so he decides to write a program to help him.this
The input contains exactly one test case.spa
In the test case there will be a line consisting of of two integers: n and m (n ≤ 1,000, m ≤ 500). The following m lines each contain two integers ai and bi, which denote the endpoints of the ith wire. Every point will have at most one link..net
Output a line, either “panda is telling the truth...” or “the evil panda is lying again”.code
4 2
0 1
3 2blog
panda is telling the truth...排序
在一个圆上有n个点(依从从0~n-1编号)。再给定m组点,表示这两个点要相互链接,链接的方式要么在圈外,要么在圈内。询问,可否使得任意两个连线都没有交点(端点除外)?图片
若是存在交点,是什么状况?
在圆内若是有交点,例如,(0,1)(2,4)的两条连线。在图上很显然的就存在交点。观察一下,那么就是两组连线的点依次出现。
即:Link[i].a < Link[j].a < Link[i].b < Link[j].b(a始终比b小)
那么此时必定存在交点ci
再来看在圆外的状况
原谅我图画得奇丑无比(然而我已经尽力了)
咱们能够发现,若是在圆外存在交点,那么在园内一定存在交点。
因此,式子和上面如出一辙。
知道了这个边是怎么回事。题目就转换为了:对于任意两组边,若是存在相交的关系,那么他们不可以同时存在于一侧(只能一内一外)。
那么它就转换为了一个2-sat问题,每条边要么在内,要么在外。
若是2-sat问题不熟能够作一下【POI2001和平委员会】理解一下
(http://blog.csdn.net/qq_30974369/article/details/73927421)
接下来不难了,由于只须要判断可行性,因此这类2-sat就很是容易解决,连完了边,用Tarjan缩点(由于在一个强连通份量中的点要么都选,要么都不选),依次判断便可。(具体实现看看代码)
补充一下通常2-sat问题的作法:
1.根据题目含义建边
2.使用Tarjan进行缩点
3.检查每一组是否存在矛盾(某个点的选择A和选择B在同一个相连通份量里面)
4.对缩出来的点进行拓扑排序,依次染色便可(必定存在解)
若是不可以理解为何存在解,就到打开上面的连接,那个Blog里面贴了一个大佬的2-sat详解
这道题目作完了能够接着作下一道【POJ3683】
http://blog.csdn.net/qq_30974369/article/details/74025251
/* POJ 3207 Ikki's Story IV - Panda's Trick 题目大意: n个点连成一圈,指定m对点之间要有连线 能够连在圈外也能够连在圈内 问可否使全部的连线不相交 思路: 这题的点只是一个媒介 对于每一条边而言,有两种选择:在圈内/在圈外 所以是一道比较显然的2-sat问题 易证实:若两条边在圈内相交则一定在圈外相交 那么,只要经过点的位置来考虑边是否相交 用2-sat便可求解 */ #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; const int MAX=100000; struct Node { int v,next; }e[MAX]; int h[MAX],cnt=0; int n,m,dfn[MAX],low[MAX],tim=0; int Linkx[MAX],Linky[MAX]; int S[MAX],top=0; int G[MAX],group=0; bool vis[MAX]; inline void Add(int u,int v) { e[cnt]=(Node){v,h[u]}; h[u]=cnt++; } inline void Link();//连边 inline void Tarjan(int u);//缩点 int main() { memset(h,-1,sizeof(h)); cin>>n>>m; for(int i=1;i<=m;++i) { cin>>Linkx[i]>>Linky[i];//储存每条边的两个端点 Linkx[i]++;Linky[i]++;//由于是从0开始的,都加1 if(Linkx[i]>Linky[i]) swap(Linkx[i],Linky[i]);//x中存编号较小的点 } Link(); //连边 for(int i=1;i<=2*m;++i)//缩点 if(!dfn[i])Tarjan(i); for(int i=1;i<=m;i++) { if(G[i]==G[i+m]) { cout<<"the evil panda is lying again"<<endl; return 0; } } cout<<"panda is telling the truth..."<<endl; return 0; } void Link()//经过点的关系把全部的边的关系找出,转化为2-sat { for(int i=1;i<=m;++i) for(int j=i+1;j<=m;++j) { if(((Linkx[i]<=Linkx[j])&&(Linkx[j]<=Linky[i])&&(Linky[i]<=Linky[j])) ||((Linkx[i]>=Linkx[j])&&(Linkx[i]<=Linky[j])&&(Linky[j]<=Linky[i]))) { //出现交叉状况不可以同时选择 Add(i,j+m);//i内j外 Add(j,i+m);//反向边 Add(i+m,j);//i外j内 Add(j+m,i);//反向边 // i 表示第i条边连在内侧 // i+m 表示第i条边连在外侧 } } } void Tarjan(int u)//缩点 { dfn[u]=low[u]=++tim; S[++top]=u; vis[u]=true; int v; for(int i=h[u];i!=-1;i=e[i].next) { v=e[i].v; if(!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { ++group; do { v=S[top--]; vis[v]=false; G[v]=group; }while(v!=u&&top); } } /* 写在AC后面: 这题我WA了好久,并不知道本身哪里错了 只到最后,突然,发现,本身, 在,连边的,时候,尽然,没有,加{},把Add()打包。 我,真是,智障,了。。。 */