[P4782]2-SAT问题

解题关键:2-sat模板,tarjan解决。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MAXN 2000006
#define MAXM 2000106
struct edge{
    int to,nxt;
}e[MAXM];
int head[MAXN],st[MAXN],dfn[MAXN],lowest[MAXN],belong[MAXN];
bool inst[MAXN];
int n,scnt,top,tot,m;//scnt从1开始

void init(){
    memset(head,-1,sizeof head);
    scnt=top=tot=0;
}

void add_edge(int u, int v){
    e[tot].to=v;
    e[tot].nxt=head[u];
    head[u]=tot++;
}

void Tarjan(int u){
    dfn[u]=lowest[u]=++tot;
    inst[u]=1;
    st[top++]=u;
    for(int i=head[u];i!=-1;i=e[i].nxt){
        int v=e[i].to;
        if(!dfn[v]){
            Tarjan(v);
            lowest[u]=min(lowest[u],lowest[v]);
        }
        else if(inst[v]){
            lowest[u]=min(lowest[u],dfn[v]);//也可用lowest
        }
    }
    if(dfn[u]==lowest[u]){
        scnt++;
        int t;
        do{
            t=st[--top];
            inst[t]=false;
            belong[t]=scnt;
        }while(t!=u);
    }
}

int main(){
    init();
    int a,x,b,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&a,&x,&b,&y);
        //左0右1
        add_edge(a<<1|(x^1),b<<1|y);//一个假,一定推出来另一个真
        add_edge(b<<1|(y^1),a<<1|x);
    }
    for(int i=2;i<=2*n+1;i++){
        if(!dfn[i]) Tarjan(i);
    }
    for(int i=1;i<=n;i++){
        if(belong[2*i]==belong[2*i+1]){
            puts("IMPOSSIBLE");
            return 0;
        }
    }
    puts("POSSIBLE");
    //构造出的解
    for(int i=1;i<=n;i++){
        if(belong[2*i]<belong[2*i+1]) printf("0 ");
        else printf("1 ");
    }
    return 0;
}

 

posted @ 2019-02-09 17:28  Elpsywk  阅读(118)  评论(0编辑  收藏  举报