POJ3207

来源:互联网 发布:c语言编写2048小游戏 编辑:程序博客网 时间:2024/06/16 18:00

Problem : Ikki’s Story IV - Panda’s Trick
Description :

有N个点顺时针排列围城一个圆形,现在在某两个点之间连边,边可以在圆形的内部,也可以在外部,但是唯一要求的是所有的边不能相交。现在问你这个东西可能不。

Solution :

2SAT问题。关键还是在于建边。我们还是要扣住2-SAT问题的关键,变量取值的二面性,那么这个题就很好办了,我们把边作为变量,在内部与在外部可以作为取值。于是我们现在就要去寻找关系了。如果两条边在圆形的内部相交,那么这两个区间(圆形上的两个点构成圆弧区间),一定是相交但不包含的,这个很好理解,画个图就知道了。内部相交,那么这两条边就必须一个在外部一个在内部了,建4条边就好了。这里我们用tarjan算法求强连通分量然后缩点的方式判断。这也是我的2-SAT问题的入门题。

Code(C++) :

#include <stdio.h>#include <string.h>#define MIN(a,b) ((a)>(b)? (b):(a))const int M=500*2+50;bool map[M][M];int n,m;int dfn[M],low[M];int belong[M];bool used[M];int after_deal_n;int que[M*10];int top;int X[M],Y[M];void swap_int(int &a,int &b){    int tmp=a;    a=b;    b=tmp;}void tarjan(int x,int sum){    dfn[x]=low[x]=++sum;    que[top++]=x;    used[x]=true;    for(int i=1;i<=2*m;i++){        if(map[x][i]){            if(!dfn[i]){                tarjan(i,sum);                low[x]=MIN(low[x],low[i]);            }else if(used[i])                low[x]=MIN(low[x],dfn[i]);        }    }    if(dfn[x]==low[x]){        ++after_deal_n;        int node;        do{            node=que[--top];            used[node]=false;            belong[node]=after_deal_n;        }while(node!=x);    }}int main(){    //freopen("in.data","r",stdin);    while(~scanf("%d%d",&n,&m)){        memset(map,false,sizeof(map));        for(int i=1;i<=m;i++){            scanf("%d%d",&X[i],&Y[i]);            if(++X[i]>++Y[i])                swap_int(X[i],Y[i]);        }        for(int i=1;i<m;i++)            for(int j=i+1;j<=m;j++)                if((X[i]<X[j]&&X[j]<=Y[i]&&Y[j]>Y[i])||(X[i]<=Y[j]&&Y[j]<=Y[i]&&X[i]>X[j]))                    map[i][j+m]=map[j][i+m]=true,                    map[j+m][i]=map[i+m][j]=true;        memset(dfn,0,sizeof(dfn));        memset(low,0,sizeof(low));        memset(belong,-1,sizeof(belong));        memset(used,false,sizeof(used));        after_deal_n=0;        top=0;        for(int i=1;i<=2*m;i++)            if(!dfn[i])                tarjan(i,0);        bool ans=true;        for(int i=1;i<=2*m;i++)            if(belong[i]==belong[i+m]){                ans=false;                break;            }        puts(ans? "panda is telling the truth...":"the evil panda is lying again");    }    return 0;}
0 0