zoukankan      html  css  js  c++  java
  • 2-SAT

     

    n个布尔变量,满足m个如 A为x或B为y的限制

    建一个点拆成两个,分别表示选TRUE或FALSE

    建立A的!x B的y 的连边 与 A的x B的!y 的连边 

    每次dfs。

    若一个点在之前条件下无论选TRUE或FALSE都无法满足条件,则无论如何都无法满足条件故无需回溯

    ——————————————————————————————————————————————

    正解tarjan(BZOJ1997)

    #include <cstdio>
    #include <iostream>
    using namespace std;
     
      int pos[10001],x[10001],y[10001],mark[10001],sta[10001],top,nd[10001],next[2000001],des[2000001],nm;
      int tx[10001],ty[10001],ham[10001],forb[10001][2],cnt,dfn[10001],low[10001],inst[10001],sct;
      int scc[10001];
     
      void addedge(int x,int y){
        next[++cnt]=nd[x];des[cnt]=y;nd[x]=cnt;
      }
     
      int check(int t1,int t2,int t3){
        if (t1==t2||t1==t3) return(0);
        if (t1>t2&&t1<t3) return(1);
        return(-1);
      }
       
      int inter(int a,int b){
        int t1=pos[x[a]],t2=pos[y[a]],t3=pos[x[b]],t4=pos[y[b]];
        if (t1>t2){
          int t=t1;t1=t2;t2=t;  
        }
        int ch1=check(t3,t1,t2),ch2=check(t4,t1,t2);
        return(ch1*ch2);
      }
     
      void tarjan(int po){
        dfn[po]=low[po]=++cnt;
        inst[po]=1;sta[++top]=po;
        for (int p=nd[po];p!=-1;p=next[p]){
          if (!dfn[des[p]]){
            tarjan(des[p]);low[po]=min(low[po],low[des[p]]);
          }else
          if (inst[des[p]]) low[po]=min(low[po],dfn[des[p]]);
        }
         
        if (low[po]==dfn[po]){
          sct++;
          while (sta[top]!=po){
            scc[sta[top]]=sct;
            inst[sta[top--]]=0;
          } 
          scc[sta[top]]=sct;
          inst[sta[top--]]=0;
        }
      }
       
      int solve(){
        for (int i=0;i<2*nm+2;i++)
          if (!dfn[i]){
            top=0;
            tarjan(i);  
          }
        for (int i=0;i<2*nm+2;i+=2)
          if (scc[i]==scc[i^1]) return(0);
        return(1);    
      }
       
     
      int main(){
        int T;
        scanf("%d",&T);
        while (T--){
          int n,m;
          scanf("%d%d",&n,&m);
          for (int i=1;i<=m;i++) scanf("%d%d",&tx[i],&ty[i]);
          for (int i=1;i<=n;i++) scanf("%d",&ham[i]);
          if (m>3*n-6) {printf("NO
    ");continue;}
          for (int i=1;i<n;i++) forb[ham[i]][0]=ham[i+1];forb[ham[n]][0]=ham[1];
          for (int i=2;i<=n;i++) forb[ham[i]][1]=ham[i-1];forb[ham[1]][1]=ham[n];
          for (int i=1;i<=n;i++) pos[ham[i]]=i;
          nm=-1;
          for (int i=1;i<=m;i++)
            if (ty[i]!=forb[tx[i]][0]&&ty[i]!=forb[tx[i]][1])
              x[++nm]=tx[i],y[nm]=ty[i];
           
          cnt=0;
          for (int i=0;i<2*nm+2;i++) nd[i]=-1,dfn[i]=0,low[i]=0,scc[i]=0;
          for (int i=0;i<=nm;i++)
            for (int j=i+1;j<=nm;j++)
              if (inter(i,j)<0){
                addedge(2*i,2*j+1);
                addedge(2*j,2*i+1);
                addedge(2*i+1,2*j);
                addedge(2*j+1,2*i);
              }
         
          cnt=0;sct=0;
          if (solve()) printf("YES
    ");else printf("NO
    ");       
        }
      }
    

     寻找方案时若有方案存在,则无需考虑#include <cstdio>

    
      int n,m,nd[2001],next[8001],des[8001],cnt,mark[2001],sta[2001],top;
      char ans[2001];
    
      void addedge(int x,int y){
          next[++cnt]=nd[x];des[cnt]=y;nd[x]=cnt;
      }
      
      int check(int po){
        if (mark[po]) return(1);
        if (mark[po^1]) return(0);
        mark[po]=1;
        sta[++top]=po;
        for (int p=nd[po];p!=-1;p=next[p])
          if (!check(des[p])) 
            return(0);
        return(1);    
      }
    
      int main(){
          scanf("%d%d",&n,&m);
          for (int i=0;i<2*n;i++) nd[i]=-1;
          for (int i=1;i<=m;i++){
            int po1,typ1,po2,typ2;char st[2];
            scanf("%d",&po1);po1--;scanf("%s",&st);typ1=(st[0]=='Y');    
            scanf("%d",&po2);po2--;scanf("%s",&st);typ2=(st[0]=='Y');
          addedge(2*po1+!typ1,2*po2+typ2);
          addedge(2*po2+!typ2,2*po1+typ1);    
        }
        for (int i=0;i<2*n;i+=2){
          top=0;int t1=check(i);
          for (int j=1;j<=top;j++) mark[sta[j]]=0;
          top=0;int t2=check(i^1);
          for (int j=1;j<=top;j++) mark[sta[j]]=0;
          if (!t1&&!t2)    {printf("IMPOSSIBLE
    ");return(0);}
          if (t1&&t2) ans[i>>1]='?';else if (t1) ans[i>>1]='N';else ans[i>>1]='Y';
        }
        for (int i=0;i<n;i++) printf("%c",ans[i]);
      }
  • 相关阅读:
    八大排序
    链表的合并
    记录B站yxc的背包九讲相关代码
    C++中多态实现
    YOLOV4所用到的一些tricks
    C++中的string 和 stringstream 的知识
    博客园中插入视频
    博客园中插入网页
    面试前必须要知道的【可重入锁 自旋锁】
    面试前必须要知道的【乐观锁 悲观锁】
  • 原文地址:https://www.cnblogs.com/zhujiangning/p/6201632.html
Copyright © 2011-2022 走看看