【2-SAT】bzoj1823 [JSOI2010]满汉全席

(A,B)中必选一个 我们可以认为选A′必选B,选B'必选必选A

tarjan缩点 同一个强连通分量的点可以互相推出 即如果选A必选A‘ 选A’必选A 显然无解

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=200+5,M=2000+5;
int n,m;
inline int read()
{    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int num,last[N],nxt[M],ver[M];
inline void add(int x,int y) {nxt[++num]=last[x]; last[x]=num; ver[num]=y;}
 
int cnt,pre[N],low[N],top,s[N],id,scc[N];
void tarjan(int x)
 {pre[x]=low[x]=++cnt;
  s[++top]=x;
   
  for(int i=last[x];i;i=nxt[i])
   {int y=ver[i];
    if(!pre[y])
     {tarjan(y);
      low[x]=min(low[x],low[y]);
     }
    else  if(!scc[y]) low[x]=min(low[x],pre[y]);
   }
    
  if(low[x]==pre[x])
   {id++; 
    while(1)
     {scc[s[top]]=id;
      if(x==s[top--]) break;
     }
   } 
 }
int main()
{
 int t,x,y; scanf("%d",&t); char r1[5],r2[5];
     
 while(t--) 
  {num=cnt=top=id=0; 
   memset(last,0,sizeof(last)); memset(pre,0,sizeof(pre));
   memset(low,0,sizeof(low));   memset(s,0,sizeof(s));
   memset(scc,0,sizeof(scc));
   scanf("%d%d",&n,&m);
     
    while(m--)
        {
            while(x!='m'&&x!='h') x=getchar();
            int a=read();
            while(y!='m'&&y!='h') y=getchar();
            int b=read();
            if(x=='m') 
                if(y=='h') add(a+n,b+n),add(b,a);
                else add(a+n,b),add(b+n,a);
            else
                if(y=='h') add(a,b+n),add(b,a+n);
                else add(a,b),add(b+n,a+n);
            x='0';y='0';
        }
    
    for(int i=1;i<=2*n;i++)
     if(!pre[i])tarjan(i);
      
   bool biao=1;
     for(int i=1;i<=n;i++)
      if(scc[i]==scc[i+n])
      {printf("BAD\n");   biao=0; break;}
       
     if(biao)printf("GOOD\n"); 
  }     
return 0;
}

 

posted @ 2018-09-21 20:22  YuXiaoze  阅读(92)  评论(0编辑  收藏  举报