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

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