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 }