POJ 3207 2_sat

来源:互联网 发布:golang docker 编辑:程序博客网 时间:2024/05/16 06:35
//poj 3207 2_sat 第一题//为什么觉得和连通分量很像呢。。//扯蛋的题意:平面上有一个圆,圆的边上按顺时针放着0..n-1共n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接//,也可以从圆的外部连接。给你的信息中,每个点最多只能连一条边。问是否可以连接这m条边,使这些边都不相交。//把边看成2-sat,因为每一条边只有两种状态,在圆内和园外两种可能,这样就满足了2-sat状态了。每两条ab和cd边可能相交情况为://(c<a && a<d && d<b)|| (a<c && c<b && b<d)。内边:2*i,外边:2*i+1//POJ 3207//题意:平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,//比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。//给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,//使这些边都不相交。////思路:对于每条Link,要么在圆外,要么在圆内,且不可同时满足,//只能两者取一,判断这M条Link是否合法,也就是M条Link不冲突,//这就是典型的2-sat问题了。 将每条Link i 看做一个点,如果Link在圆内,//则选做i ,如果在圆外, 则选做i'。对于两条线(i,j) ,如果i,j不能同时//在圆内,也就可以推出两者不能同时在圆外,这个证明很容易,读者可//以自行证明。i, j不能同时在圆内,则有边(i, j') 、(j ,i')、(i',j)、(j' ,i)//(这是由2-sat的构图方式决定的,具体可以看《由对称性解2-SAT问题》// 这篇论文)。建图完了之后,本题就是判断2-sat问题是否有解,// 先求原图的强连通分量,并缩点,(这里我们称:(i,i')属于同一组),// 判断是否存在(i,i')属于同一组,若存在,则不可能,若不存在则可能。////最后看是不有有一对点在同一个连通分量//明明是传说中的2-sat,为什么我怎么看怎么像水题。。//一开始栈开得不够。。不过为什么/////我每条边建了4条边//双向边什么的要注意多建一点边过的代码。#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<algorithm>#include<string>#include<vector>#include<queue>#define maxn 1050using namespace std;///我每条边建了4条边struct Edge{    int from, to, nex;    bool sign;//是否为桥}edge[60*maxn];int head[maxn], edgenum;void addedge(int u, int v){    Edge E={u, v, head[u], false};    edge[edgenum] = E;    head[u] = edgenum++;}int DFN[maxn], Low[maxn], Stack[maxn], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)int taj;//连通分支标号,从1开始int Belong[maxn];//Belong[i] 表示i点属于的连通分支bool Instack[maxn];vector<int> bcc[maxn]; //标号从1开始void tarjan(int u ,int fa)//求出图的强联通分量{    DFN[u] = Low[u] = ++ Time ;    Stack[top ++ ] = u ;    Instack[u] = 1 ;    for (int i = head[u] ; ~i ; i = edge[i].nex ){        int v = edge[i].to ;        if(DFN[v] == -1)        {            tarjan(v , u) ;            Low[u] = min(Low[u] ,Low[v]) ;            if(DFN[u] < Low[v])            {                edge[i].sign = 1;//为割桥            }        }        else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ;    }    if(Low[u] == DFN[u]){        int now;        taj ++ ;bcc[taj].clear();        do{            now = Stack[-- top] ;            Instack[now] = 0 ;            Belong [now] = taj ;            bcc[taj].push_back(now);        }while(now != u) ;    }}void tarjan_init(int all){    memset(DFN, -1, sizeof(DFN));    memset(Instack, 0, sizeof(Instack));    top = Time = taj = 0;    for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!!}vector<int>G[maxn];void init(){memset(head, -1, sizeof(head)); edgenum=0;}int U[maxn],V[maxn];bool judge(int x,int y){  //  cout<<"miao"<<endl;    int a=U[x];    int b=V[x];    int c=U[y];    int d=V[y];    if((a<c && c<b && b<d) || (a<d && d<b && c<a))        return true;    else        return false;}int n,m;int main(){while(scanf("%d%d",&n,&m)!=EOF){    for(int i=1;i<=m;i++)    {        scanf("%d%d",&U[i],&V[i]);        U[i]++;V[i]++;    }    init();    for(int i=1;i<m;i++)        for(int j=i+1;j<=m;j++)    {        if(judge(i,j))///相交        {            addedge(2*i-1,2*j);            addedge(2*j,2*i-1);            addedge(2*i,2*j-1);            addedge(2*j-1,2*i);        }    }   tarjan_init(m*2);   bool flag=true;   for(int i=1;i<=m;i++)    {        if(Belong[2*i-1]==Belong[2*i])         {flag=false;break;}    }    if(flag)        cout<<"panda is telling the truth..."<<endl;    else        cout<<"the evil panda is lying again"<<endl;}}

0 0