zoukankan      html  css  js  c++  java
  • P4782 【模板】2-SAT 问题

    芝士

    2-SAT问题就是一种给出n个变量,满足一些二元限制比如(x取1,y必须取0),要求求出n个变量赋值的合法方案的题目
    3-SAT及更多是NP完全问题
    2-SAT求解可以用tarjan,时间复杂度(O(n+m)),但是要求输出字典序最小解的时候只有(O(nm))的算法
    算法流程就是要拆点连边,x表示x取1,x+n表示x取0,然后用边表示“必须”的条件,<x,y+n>表示x取1,y必须取0,则如果选了x,相连的所有点都要选
    所以处于同一强连通分量里的点必须都选,无解显然是x与x+n在一个强连通分量中
    输出方案的时候,为了避免冲突和保证能构造出解,需要在缩点之后的DAG里找到拓扑序的反序小的点先选(就是对后面没有影响的,因为选了x之后后面的点都要选),tarjan之后的sccno正好是反向的拓扑序,所以优先选标号小的条件即可

    思路

    板子,转化成x为a^1时y必须为b、y为b^1时x必须为a即可

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    using namespace std;
    int u[2000100],v[2000100],fir[2000100],nxt[2000100],cnt,low[2000100],dfn[2000100],dfs_clock,vis[2000100],scc_cnt,sccno[2000100],n,m,choose[2000100];
    stack<int> S;
    void addedge(int ui,int vi){
        ++cnt;
        u[cnt]=ui;
        v[cnt]=vi;
        nxt[cnt]=fir[ui];
        fir[ui]=cnt;
    }
    void tarjan(int u){
        low[u]=dfn[u]=++dfs_clock;
        S.push(u);
        vis[u]=true;
        for(int i=fir[u];i;i=nxt[i]){
            if(!dfn[v[i]]){
                tarjan(v[i]);
                low[u]=min(low[u],low[v[i]]);
            }
            else if(vis[v[i]])
                low[u]=min(low[u],low[v[i]]);
        }
        if(low[u]==dfn[u]){
            scc_cnt++;
            while(1){
                int x=S.top();
                S.pop();
                vis[x]=false;
                sccno[x]=scc_cnt;
                if(x==u)
                    break;
            }
        }
    }
    void get_scc(void){
        for(int i=1;i<=2*n;i++)
            if(!dfn[i])
                tarjan(i);
    }
    int main(){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++){
            int xi,xj,a,b;
            scanf("%d %d %d %d",&xi,&a,&xj,&b);
            addedge(xi+(a^1)*n,xj+b*n);
            addedge(xj+(b^1)*n,xi+a*n);
        }
        get_scc();
        bool f=true;
        for(int i=1;i<=n;i++){
            if(sccno[i]==sccno[i+n]){
                f=false;
                break;
            }
            if(sccno[i]<sccno[i+n])
                choose[i]=0;
            else
                choose[i]=1;
        }
        if(!f){
            printf("IMPOSSIBLE
    ");
        }
        else{
            printf("POSSIBLE
    ");
            for(int i=1;i<=n;i++)
                printf("%d ",choose[i]);
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    node.js
    js中文乱码问题
    238. Product of Array Except Self
    接下来要记得东西
    javascript 块内函数
    171. Excel Sheet Column Number
    Moore’s Voting Algorithm
    [ Python ] PIL
    [ Python ] KMP Algorithms
    房之事
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10610525.html
Copyright © 2011-2022 走看看