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\n");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\n");else printf("NO\n");       
    }
  }

 寻找方案时若有方案存在,则无需考虑#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\n");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]);
  }

 

posted @ 2016-12-20 10:28  z1j1n1  阅读(167)  评论(0编辑  收藏  举报