[模板] 2-SAT


昨天早上在准备省队集训,发现自己连\(2-SAT\)是什么都不知道,于是一早上都投身于\(2-SAT\)模板中,终于有个结果。

思路如下:

1.根据条件表达式建边:\((x,y)\)表示如果选了\(x\)必须选\(y\)

2.缩环;

3.判断是否可行;

4.根据缩完环的图反向建边;

5.拓扑排序进行染色(\(1\)表示\(true,2\)表示\(false\))。

时间复杂度:\(O(n+m)\)

/*假设输入是无空格无括号的的c++条件表达式且未知数用编号代替*/

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define L 11
#define N 100001
#define M 1000001
using namespace std;
struct graph{
    int nxt,to;
}e[M],gra[M];
int sol[N],col[N];
int f[N],dfn[N],low[N],sta[N];
int g[N],go[N],to[N],n,m,nn,cnt;
bool ins[N];char c[L];queue q;
inline addedge(int x,int y){
    e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
inline adde(int x,int y){
    gra[++cnt].nxt=go[x];go[x]=cnt;gra[cnt].to=y;
}
inline void type(){
    int l=strlen(c),i=0,x=0,y=0;
    bool flag1=true,flag2=true;
    if(c[i]=='!'){
        flag1=false;i++;
    }
    while(i='0'&&c[i]<='9')
        x=x*10+c[i++]-'0';
    if(i==l){
        if(flag1) addedge(x+n,x);
        else addedge(x,x+n);
        return;
    }
    char cha=c[i];i++;
    if(c[i]=='!'){
        flag2=false;i++;
    }
    while(i='0'&&c[i]<='9')
        y=y*10+c[i++]-'0';
    if(cha=='&'){
        if(flag1&&flag2){
            addedge(x+n,x);
            addedge(y+n,y);
        }
        else if(flag1){
            addedge(x+n,x);
            addedge(y,y+n);
        }
        else if(flag2){
            addedge(x,x+n);
            addedge(y+n,y);
        }
        else{
            addedge(x,x+n);
            addedge(y,y+n);
        }
    }
    else if(cha=='|'){
        if(flag1&&flag2){
            addedge(x+n,y);
            addedge(x,y+n);
        }
        else if(flag1){
            addedge(x+n,y+n);
            addedge(y,x);
        }
        else if(flag2){
            addedge(x,y);
            addedge(y+n,x+n);
        }
        else{
            addedge(x,y+n);
            addedge(y,x+n);
        }
    }
    else if(cha=='^'){
        if(flag1&&flag2){
            addedge(x,y+n);
            addedge(x+n,y);
            addedge(y,x+n);
            addedge(y+n,x);
        }
        else if(flag1){
            addedge(x,y);
            addedge(x+n,y+n);
            addedge(y,x);
            addedge(y+n,x+n);
        }
        else if(flag2){
            addedge(x,y);
            addedge(x+n,y+n);
            addedge(y,x);
            addedge(y+n,x+n);
        }
        else{
            addedge(x,y+n);
            addedge(x+n,y);
            addedge(y,x+n);
            addedge(y+n,x);
        }
    }
}
inline void tarjan(int u){
    dfn[u]=low[u]=++cnt;
    sta[++sta[0]]=u;ins[u]=true;
    for(int i=g[u];i;i=e[i].nxt)
        if(!dfn[e[i].to]){
            tarjan(e[i].to);
            low[u]=min(low[u],low[e[i].to]);
        }
        else if(ins[e[i].to])
            low[u]=min(low[u],low[e[i].to]);
    if(dfn[u]==low[u]){
        while(sta[sta[0]+1]!=u){
            f[sta[sta[0]]]=u;
            ins[sta[0]--]=false;
        }
    }
}
inline bool chk(){
    for(int i=1;i<=n;i++)
        if(f[i]==f[i+n]) return false;
    return true;
}
inline void build(){
    cnt=0;
    for(int i=1;i<=nn;i++)
        for(int j=g[i];j;j=e[j].nxt){
            if(f[i]!=f[e[j].to]){
                adde(f[e[j].to],f[i]);to[i]++;
            }
        }
}
inline void toposort(){
    for(int i=1;i<=nn;i++)
        if(f[i]==i&&!to[i]) q.push(i);
    while(!q.empty()){
        int u=q.front();q.pop();
        if(!col[u]){
            col[u]=1;col[u+n]=-1;
        }
        for(int i=go[u];i;i=gra[i].nxt)
            if(!(--to[gra[i].to]))
                q.push(gra[i].to);
    }
}
inline void init(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%s",&c);type();
    }
    nn=n<<1;cnt=0;
    for(int i=1;i<=nn;i++)
        if(!dfn[i]) tarjan(i);
    if(!chk()){
        printf("No solution.\n");
        return;
    }
    build();
    toposort();
    for(int i=1;i<=n;i++)
        col[i]=col[f[i]];
    for(int i=1;i<=n;i++)
        if(col[i]>0) printf("%d:true\n",i);
        else printf("%d:false\n",i);
}
int main(){
    freopen("2sat.in","r",stdin);
    freopen("2sat.out","w",stdout);
    init();
    fclose(stdin);
    fclose(stdout);
    return 0;
}