poj3207 Ikki's Story IV - Panda's Trick(2-sat)

看了半天,看不懂题意。
题意
在一个圆上分布有n个点,现在要在这n个点之间连上m条边,每条边可以从圆内连接,也可以在圆外连接,每个点只能连接一条边,求是否存在连接方案能使得这m条边不相交。
看图容易懂题意。。。。。。
2-sat
那么
对于两条线(这道题的节点可以认为是线,i<<1表示第i条线外连,i<<1|1表示第i条线内连。),矛盾的必要条件是(不妨设line[i].a< line[j].a)
line[j].a< line[i].b&&line[i].b< line[j].b。满足这个必要条件并不一定矛盾,只需(i内连&&j外连)||(i外连&&j内连)
看似不是2-sat问题,其实
转化一下(数理逻辑的知识),就等于
(i内连||j内连)&&(i外连||j外连)
2-sat问题就是一个合取范式。
所以就相当于两个析取式(i内连||j内连)和(i外连||j外连)。
接着就是2-sat问题的解法了。
由于这道题只需判断是否矛盾,所以就可以直接求强连通,然后看是否有某个Belong[i<<1]和Belong[i<<1|1](对于这道题,每条线只能选择内连或者外连之一,也就相当于要么内连为真,要么内连为假两种情况,用i<<1代表内连为真,i<<1|1代表内连为假,如果他们在一个强连通分量中则说明他们要么同时取,要么同时不去,但是它们事实上必须取并且只能取其中一个。)是否相等。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=1010;
const int MAXM=1e6+5;
struct _Edge
{
    int to,next;
}edge[MAXM];
int hd[MAXN],tot;
void inti(void)
{
    tot=0;
    msc(hd);
}
void addedge(int u,int v)
{
    edge[tot].to=v,edge[tot].next=hd[u];
    hd[u]=tot++;

    //printf("   %d to %d\n",u,v );
}
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
void Tarjan(int u)
{
    int v;
    Low[u]=DFN[u]=++Index;
    Stack[top++]=u;
    Instack[u]=true;
    for(int i=hd[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].to;
        if(!DFN[v])
        {
            Tarjan(v);
            if(Low[u]>Low[v]) Low[u]=Low[v];
        }
        else if(Instack[v]&&Low[u]>DFN[v])
            Low[u]=DFN[v];
    }
    if(Low[u]==DFN[u])
    {
        scc++;
        do{
            v=Stack[--top];
            Instack[v]=false;
            Belong[v]=scc;
        }while(v!=u);
    }
}
struct _Line
{
    int a,b;
}line[MAXN>>1];
int cmp(const void *p,const void *q)
{return ((struct _Line *)p)->a-((struct _Line *)q)->a;}
int main(int argc, char const *argv[])
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        if(a<b) line[i].a=a,line[i].b=b;
        else line[i].a=b,line[i].b=a;
    }
    qsort(line,m,sizeof(struct _Line),cmp);
    inti();
    for(int i=0;i<m;i++)
        for(int j=i+1;j<m;j++)
            if(line[j].a<line[i].b&&line[i].b<line[j].b)
            {
                addedge(i<<1,j<<1|1);
                addedge(j<<1,i<<1|1);
                addedge(i<<1|1,j<<1);
                addedge(j<<1|1,i<<1);
            }
    ms(DFN);
    ms(Instack);
    Index=scc=top=0;
    for(int i=0;i<2*m;i++)
        if(!DFN[i]) Tarjan(i);
    for(int i=0;i<2*m;i+=2)
        if(Belong[i]==Belong[i^1])
            {
                puts("the evil panda is lying again");
                return 0;
            }
    puts("panda is telling the truth...");
    return 0;
}
/*
6 3
0 3
1 4
2 5

*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章