POJ 3207 Ikki's Story IV - Panda's Trick(2-SAT)

题意

平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,使这些边都不相交。(n<=1000,m<=500)

题解

我们把一条边在圆里和圆外作为a和!a,当两条边一个在圆里另一个必定在圆外时我们将它们连边(a,!b)(!a,b)(b,!a)(!b,a)。然后跑Tarjan最后判断如果存在一个a和!a在一个强联通分量里就为false。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=1010;
 8 int cnt,head[N];
 9 int dfn[N],low[N],book[N],stack[N],tot,top,num,col[N];
10 int n,m,a[N],b[N];
11 struct edge{
12     int to,nxt;
13 }e[N*N];
14 void add(int u,int v){
15     cnt++;
16     e[cnt].nxt=head[u];
17     e[cnt].to=v;
18     head[u]=cnt;
19 }
20 void Tarjan(int u){
21     dfn[u]=low[u]=++tot;
22     book[u]=1;
23     stack[++top]=u;
24     for(int i=head[u];i;i=e[i].nxt){
25         int v=e[i].to;
26         if(dfn[v]==0){
27             Tarjan(v);
28             low[u]=min(low[u],low[v]);
29         }
30         else if(book[v])low[u]=min(low[u],dfn[v]);
31     }
32     if(low[u]==dfn[u]){
33         num++;
34         int x;
35         do{
36             x=stack[top--];
37             col[x]=num;
38             book[x]=0;
39         }while(x!=u);
40     }
41 }        
42 int main(){
43     scanf("%d%d",&n,&m);
44     for(int i=1;i<=m;i++){
45         scanf("%d%d",&a[i],&b[i]);
46         if(a[i]>b[i])swap(a[i],b[i]);
47     }
48     for(int i=1;i<=m;i++)
49         for(int j=i+1;j<=m;j++){
50             if((a[j]<a[i]&&a[i]<b[j])^(a[j]<b[i]&&b[i]<b[j])){
51                 add(i,j+m);add(i+m,j);add(j,i+m);add(j+m,i);
52             }
53         }
54     for(int i=1;i<=n;i++){
55         if(!dfn[i])Tarjan(i);
56     }
57     for(int i=1;i<=m;i++){
58         if(col[i]==col[i+m]){
59             printf("the evil panda is lying again");
60             return 0;
61         }
62     }
63     printf("panda is telling the truth...");
64     return 0;
65 }
View Code

 

posted @ 2018-07-29 21:34  Xu-daxia  阅读(147)  评论(0编辑  收藏  举报