• P4782 【模板】2-SAT 问题


    P4782 【模板】2-SAT 问题

    将每个数的真假分成两个点$i+n,i$

    $a$真或$b$假

    $=a$假$b$必假,$b$真$a$必真

    $=a->b,b+n->a+n$

    以此类推建边

    如果$x,x+n$在同一个强连通分量里,就不成立

    用Tarjan判断。

    注意有$2n$个点,每个都要跑Tarjan

    询问可行做法时,我们总是取$x,x+n$中拓扑序靠后的那个

    也就是连通块编号小的(因为是dfs)

    连边时用的是位运算

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    const int N=2000003;
    vector <int> g[N];
    int n,m,dfn[N],low[N],K,be[N],B,st[N],tp;
    void Tar(int x){
        dfn[x]=low[x]=++K; st[++tp]=x;
        for(int i:g[x]){
            if(!dfn[i]) Tar(i),low[x]=min(low[x],low[i]);
            else if(!be[i]) low[x]=min(low[x],dfn[i]);
        }
        if(dfn[x]==low[x]){
            be[x]=++B;
            for(;st[tp]!=x;--tp) be[st[tp]]=B;
            --tp;
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1,q,w,e,r;i<=m;++i){
            scanf("%d%d%d%d",&q,&w,&e,&r);
            g[q+n*(w^1)].push_back(e+n*r);
            g[e+n*(r^1)].push_back(q+n*w);
        }
        for(int i=1;i<=n*2;++i) if(!dfn[i]) Tar(i);
        for(int i=1;i<=n;++i)
            if(be[i]==be[i+n]){
                puts("IMPOSSIBLE");
                return 0;
            }
        puts("POSSIBLE");
        for(int i=1;i<=n;++i)
            printf("%d ",be[i]>be[i+n]);
        return 0;
    }
  • 相关阅读:
    各种
    shell
    搭建个人信息平台
    基本tomcat+nginx
    vi编辑的使用
    linux权限管理
    Java观察者模式
    Flume+Kafka+Sparkstreaming日志分析
    科学计算与数学建模
    推荐系统起手式-几种简单推荐模型(基于内容的推荐)
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/15058500.html
Copyright © 2020-2023  润新知