P4782 【模板】2-SAT 问题

 

如果 I 和 I’ 在同一强连通分量中,那么肯定 I 能到达 i’ , I’ 能到达 i,所以无解。
如果 I 和 I’ 不在同一强连通分量中,那么对缩点后的新图进行拓扑排序,我们选择拓扑序大的点,而拓扑序大的点肯定是到达不了拓扑序小的点的,根据DFS做法中的证明,我们可以证明我们的选择一定合法。
而我们缩点后,如果 I 能到达 i’,则 I 所属的新点标号一定大于I’(仔细思考),那么我们只需要比较 I 和 i’ 所属的新点标号,选择较大的点即可,这样就不用再进行拓扑排序了。

#include <bits/stdc++.h>
#define inf 23333333333333
#define N 2000010
#define p(a) putchar(a)
#define For(i,a,b) for(int i=a;i<=b;++i)

using namespace std;
int n,m,a1,a2,c1,c2,flag;
void in(int &x){
    int y=1;char c=getchar();x=0;
    while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    while(c<='9'&&c>='0'){ x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    x*=y;
}
void o(int x){
    if(x<0){p('-');x=-x;}
    if(x>9)o(x/10);
    p(x%10+'0');
}

struct Graph{
    int cnt,col,now;
    int d[N],low[N],dfn[N],c[N];
    bool vis[N];
    stack<int>s;
    struct node{
        int n;
        node *next;
    }*e[N];
    void init(){
        cnt=col=0;
        For(i,0,2*n+5) e[i]=0;
        memset(d,0,sizeof d);
        memset(low,0,sizeof low);
        memset(dfn,0,sizeof dfn);
        memset(c,0,sizeof c);
        memset(vis,0,sizeof vis);
        while(!s.empty()) s.pop();
    }
    void push(int x,int y){
        node *p;
        p=new node();
        p->n=y;
        if(e[x]==0)
            e[x]=p;
        else{
            p->next=e[x]->next;
            e[x]->next=p;
        }
    }

    void tarjan(int x){
        dfn[x]=low[x]=++cnt;
        vis[x]=1;
        s.push(x);
        for(node *i=e[x];i;i=i->next){
            if(!dfn[i->n]){
                tarjan(i->n);
                low[x]=min(low[x],low[i->n]);
            }
            else
                if(vis[i->n])
                    low[x]=min(low[x],dfn[i->n]);
        }
        if(low[x]==dfn[x]){
            col++;
            do{
                now=s.top();
                c[now]=col;
                s.pop();
                vis[now]=0;
            }while(x!=now);
        }
    }
}G;

signed main(){
    while(cin>>n>>m){
        G.init();
        For(i,1,m){
            in(a1);in(c1);in(a2);in(c2);
            G.push(2*a1-c1,2*a2+c2-1);
            G.push(2*a2-c2,2*a1+c1-1);
        }
        For(i,1,2*n)
            if(!G.dfn[i]) G.tarjan(i);
        flag=0;
        for(int i=1;i<=2*n;i+=2){
            if(G.c[i]==G.c[i+1]){
                flag=1;
                break;
            }
        }
        if(flag) puts("IMPOSSIBLE");
        else{
            puts("POSSIBLE");
            for(int i=1;i<=2*n;i+=2){
                if(G.c[i]>G.c[i+1]){
                    o(1);
                }else{
                    o(0);
                }
                p(' ');
            }
            p('\n');
        }
    }   
    return 0;
}

 

posted @ 2020-08-04 11:19  WeiAR  阅读(121)  评论(0编辑  收藏  举报