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

    传送门

    2-SAT的板子

    把每一个点拆成选0或选1

    条件为$x_i$为$a$或$x_j$为$b$,那么如果$x_i$不为$a$则$x_j$必为$b$,同理$x_j$不为$b$则$x_i$必为$a$

    那么从$x_i$不为$a$的点向$x_j$为$b$的点连边,从$x_j$不为$b$的点向$x_i$为$a$的点连边

    然后跑一个tarjan缩点,在新的DAG的反图上跑一遍拓扑排序,如果有一个点的两个取值在同一个强连通分量里就无解,否则取两个取值中拓扑序小的那一个

    有一个小技巧就是tarjan缩点时的编号实际就是新的DAG的反图拓扑序,那么只要看两个取值谁的拓扑序更小取谁就行了

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 using namespace std;
     5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     6 char buf[1<<21],*p1=buf,*p2=buf;
     7 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
     8 inline int read(){
     9     #define num ch-'0'
    10     char ch;bool flag=0;int res;
    11     while(!isdigit(ch=getc()))
    12     (ch=='-')&&(flag=true);
    13     for(res=num;isdigit(ch=getc());res=res*10+num);
    14     (flag)&&(res=-res);
    15     #undef num
    16     return res;
    17 }
    18 char sr[1<<21],z[20];int C=-1,Z;
    19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    20 inline void print(int x){
    21     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    22     while(z[++Z]=x%10+48,x/=10);
    23     while(sr[++C]=z[Z],--Z);sr[++C]=' ';
    24 }
    25 const int N=2e6+5;
    26 int head[N],Next[N],ver[N],tot;
    27 inline void add(int u,int v){
    28     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
    29 }
    30 int dfn[N],bl[N],low[N],st[N],top,num,cnt,n,m;
    31 void tarjan(int u){
    32     dfn[u]=low[u]=++num,st[++top]=u;
    33     for(int i=head[u];i;i=Next[i]){
    34         int v=ver[i];
    35         if(!dfn[v]) tarjan(v),cmin(low[u],low[v]);
    36         else if(!bl[v]) cmin(low[u],dfn[v]);
    37     }
    38     if(low[u]==dfn[u]) for(++cnt;st[top+1]!=u;--top) bl[st[top]]=cnt;
    39 }
    40 int main(){
    41 //    freopen("testdata.in","r",stdin);
    42     n=read(),m=read();
    43     for(int i=1;i<=m;++i){
    44         int a=read(),b=read(),c=read(),d=read();
    45         add(a+(!b)*n,c+d*n),add(c+(!d)*n,a+b*n);
    46     }
    47     for(int i=1,l=n<<1;i<=l;++i) if(!dfn[i]) tarjan(i);
    48     for(int i=1;i<=n;++i)
    49     if(bl[i]==bl[i+n]) return puts("IMPOSSIBLE"),0;
    50     puts("POSSIBLE");
    51     for(int i=1;i<=n;++i) print(bl[i+n]<bl[i]);
    52     Ot();
    53     return 0;
    54 }
  • 相关阅读:
    Linux学习之路3-HelloWorld
    Linux学习之路2-linux系统烧写
    Linux学习之路1
    linux常用命令总结
    禅道配置发邮件功能
    SHELVE模块
    PICKLE模块
    JSON_dump和load
    json.dumps和loads方法
    模块调用
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9785768.html
Copyright © 2011-2022 走看看