2-SAT算法学习笔记

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ylsoi/article/details/81837920

2-SAT:

好像大概是这么一个东西,有一些集合,每个集合中有两个元素(ai,bi),然后要求你从每一个集合中选出一个元素,但是同时对于集合元素的选取是有一些限制的,比如说什么选了aiaj必须选一个,或者选了ai就必须选bj之类的。
然后我们发现上面所有的限制条件都可以转化为一类,即选了ai就必须选择bj这种。
然后解决这种问题算法就是建立一个有向图,对于选ai就必须选bj这种限制,我们在图中从ai连向bj,同时我们发现如果选aj也必须选bi,所以在图中从aj连向bi。不难发现这个图有对称性。
对于这个有向图,如果从ai可以到达bi,那么ai一定是不可以选的,那么根据有向图的传递性以及这个图本身的对称性,那么我们发现只有当aibi在同一强连通分量中是才有可能是无解的。
于是我们可以把图建出来之后缩强连通分量,然后判断一下有没有无解的情况,如果有解的话就直接按照拓扑序的逆序选择每个集合内的元素。
洛谷模板:

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("luogu4782.in","r",stdin);
    freopen("luogu4782.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(mul=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=1e6+10;
int n,m;
int beg[maxn<<1],to[maxn<<1],las[maxn<<1],cnte=1;
int bel[maxn<<1],cnt_scc,low[maxn<<1],dfn[maxn<<1],cnt_dfn;
stack<int>stk;

void add(int u,int v){las[++cnte]=beg[u];beg[u]=cnte;to[cnte]=v;}

void tarjan(int u){
    low[u]=dfn[u]=++cnt_dfn;
    stk.push(u);
    for(int i=beg[u];i;i=las[i]){
        if(!dfn[to[i]]){
            tarjan(to[i]);
            low[u]=min(low[u],low[to[i]]);
        }
        else if(!bel[to[i]])low[u]=min(low[u],dfn[to[i]]);
    }
    if(dfn[u]==low[u]){
        ++cnt_scc;
        for(int p;p!=u;stk.pop()){
            p=stk.top();
            bel[p]=cnt_scc;
        }
    }
}

void init(){
    read(n); read(m);
    int x,y,t1,t2;
    REP(i,1,m){
        read(x); read(t1); read(y); read(t2);
        add(x+(1-t1)*n,y+t2*n);
        add(y+(1-t2)*n,x+t1*n);
    }
}

void work(){
    REP(i,1,(n<<1))if(!dfn[i])
        tarjan(i);
    REP(i,1,n)if(bel[i]==bel[i+n]){
        puts("IMPOSSIBLE");
        return;
    }
    puts("POSSIBLE");
    REP(i,1,n){
        if(bel[i]<bel[i+n])putchar('0');
        else putchar('1');
        putchar(' ');
    }
}

int main(){
    File();
    init();
    work();
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页