1. 程式人生 > >[模板][P4782]2-SAT

[模板][P4782]2-SAT

() != int sin puts pos 問題 als con

Description:

有n個布爾變量\(x_1\)~\(x_n\),另有m個需要滿足的條件,每個條件的形式都是“\(x_i\)為true/false或\(x_j\)為true/false”。比如“\(x_1\)為真或\(x_3\)為假”、“\(x_7\)為假或\(x_2\)為假”。2-SAT 問題的目標是給每個變量賦值使得所有條件得到滿足。

Hint:

\(1\le n,m\le 10^6\)

Solution:

模板題,詳見代碼

#include <algorithm>
#include <cmath>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
const int mxn=2e6+5;
int n,m,tot,cnt,col;
int hd[mxn],bl[mxn],dfn[mxn],low[mxn],ins[mxn];
stack<int > st;

struct ed {
    int to,nxt;
}t[mxn<<1];

inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

inline void add(int u,int v) {
    t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}

void tj(int u)
{
    dfn[u]=low[u]=++tot; st.push(u); ins[u]=1;
    for(int i=hd[u];i;i=t[i].nxt) {
        int v=t[i].to;
        if(!dfn[v]) tj(v),chkmin(low[u],low[v]);
        else if(ins[v]) chkmin(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]) {
        ++col;
        do{
            bl[u]=col; u=st.top();
            st.pop(); ins[u]=0;
        } while(low[u]!=dfn[u]);
    }
} //tarjan基本操作,沒什麽好說的

int main()
{
    scanf("%d%d",&n,&m); int u,v,x,y;
    for(int i=1;i<=m;++i) {
        scanf("%d%d%d%d",&u,&x,&v,&y);
        add(u+n*(x^1),v+n*y);
        add(v+n*(y^1),u+n*x); //建邊,很好懂的
    }
    for(int i=1;i<=2*n;++i) 
        if(!dfn[i]) tj(i);
    for(int i=1;i<=n;++i) 
        if(bl[i]==bl[i+n]) {
            puts("IMPOSSIBLE");
            return 0;
        }
    puts("POSSIBLE");   
    for(int i=1;i<=n;++i) 
        printf("%d ",bl[i]>bl[i+n]);    //按較大拓撲序輸出答案
    return 0;
}

[模板][P4782]2-SAT