poj 3207 2-SAT问题

思路:将线段按开始点的升序排序,对线段尾节点进行判断,若存在交叉,那么这两条线段就不能同时在内或同时在外。这样将每条线段在内和在外看成两个状态ii',i表示线段在内,i'表示线段在外。假使线段i和线段j相交,那么ij是矛盾,且i'j'是矛盾。

具体见代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define Maxn 2010
#define Maxm Maxn*Maxn
using namespace std;
int vi[Maxn],head[Maxn],dfn[Maxn],low[Maxn],e,n,lab,top,num,m,id[Maxn],Stack[Maxn];
struct Edge{
    int u,v,next;
}edge[Maxm];
struct line{
    int u,v;
}p[Maxn];
void init()//初始化
{
    memset(vi,0,sizeof(vi));
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(id,0,sizeof(id));
    e=lab=top=num=0;
}
void add(int u,int v)//加边
{
    edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++;
}
int cmp(line a,line b)
{
    if(a.u==b.u)
        return a.v<b.v;
    return a.u<b.u;
}
void Tarjan(int u)//找出强连通分支
{
    int i,j,v;
    //cout<<u<<endl;
    dfn[u]=low[u]=++lab;
    Stack[top++]=u;
    vi[u]=1;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].v;
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        if(vi[v])
        low[u]=min(low[u],dfn[v]);

    }
    if(low[u]==dfn[u])
    {
        ++num;
        do{
            i=Stack[--top];
            vi[i]=0;
            id[i]=num;
        }while(i!=u);
    }
}
int solve()
{
    int i,j;
    for(i=1;i<=m*2;i++)
        if(!dfn[i])
        Tarjan(i);
    for(i=1;i<=m;i++)
        if(id[i]==id[i+m])
            return 0;//有矛盾则结束
    return 1;
}
int cross(line a,line b)
{
    if(a.v>b.u&&a.v<b.v)
        return 1;
    return 0;
}
int main()
{
    int i,j,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            p[i].u=a<b?a:b;
            p[i].v=a>b?a:b;
        }
        sort(p+1,p+1+m,cmp);
        for(i=1;i<m;i++)
        for(j=i+1;j<=m;j++)
        {
            if(cross(p[i],p[j]))//如果有两条线的区间相交,那么存在矛盾
            {
                add(i,j+m);
                add(j,i+m);
                add(i+m,j);
                add(j+m,i);
            }
        }
        if(solve())
            printf("panda is telling the truth...\n");
        else
            printf("the evil panda is lying again\n");
    }
    return 0;
}

 

posted @ 2013-07-28 15:27  fangguo  阅读(185)  评论(0编辑  收藏  举报