【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;
}