题意:
有
n
n
n种食材,每种食材有两种加工方式。有
m
m
m个评委,每个评委只会喜欢两种具体地某种加工方式加工后的食材。你现在要找到是否存在一种加工这
n
n
n种食材的方式,使得每个评委至少能吃到一道他喜欢的菜。多组询问。询问组数
<
=
50
,
n
<
=
100
,
m
<
=
1000
<=50,n<=100,m<=1000
<=50,n<=100,m<=1000。
题解:
是一道2-SAT的简单题吧。
就是考虑用2-SAT求解,我们把一种食材拆成两个点,表示两种不同的加工方式。我们对于每一个评委的要求来连边,由于每个评委的两个要求至少满足一个,那么如果第一种食材没有按照他想要的方式加工,那么第二种一定要用他想要的方式加工;同理如果第二种没有按照他想要的方式加工,那么第一种食材一定要按照他想要的方式加工。这个选了某一个点就一定要选某一个点的关系可以用2-SAT来表示,于是我们就连一下边,跑个2-SAT来判断是否有解就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
int T,n,m,hed[210],cnt;
int dfn[210],low[210],sta[210],tp,vis[210],num,kuai[210];
struct node
{
int to,next;
}a[4010];
inline int read()
{
int x=0;
char s=getchar();
while(s>'9'||s<'0')
s=getchar();
while(s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
return x;
}
inline void add(int from,int to)
{
a[++cnt].to=to;
a[cnt].next=hed[from];
hed[from]=cnt;
}
inline void tarjan(int x)
{
sta[++tp]=x;
dfn[x]=low[x]=++num;
vis[x]=1;
for(int i=hed[x];i;i=a[i].next)
{
int y=a[i].to;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y])
low[x]=min(low[x],low[y]);
}
if(dfn[x]==low[x])
{
++num;
while(sta[tp+1]!=x)
{
kuai[sta[tp]]=x;
vis[sta[tp]]=0;
--tp;
}
}
}
int main()
{
T=read();
while(T--)
{
memset(hed,0,sizeof(hed));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(kuai,0,sizeof(kuai));
for(int i=1;i<=cnt;++i)
{
a[i].to=0;
a[i].next=0;
}
cnt=0;
num=0;
n=read();
m=read();
for(int i=1;i<=m;++i)
{
char s=getchar();
int x,xx,y,yy;
while(s!='h'&&s!='m')
s=getchar();
x=read();
if(s=='h')
xx=x+n;
else
{
xx=x;
x+=n;
}
s=getchar();
while(s!='h'&&s!='m')
s=getchar();
y=read();
if(s=='h')
yy=y+n;
else
{
yy=y;
y+=n;
}
add(xx,y);
add(yy,x);
}
for(int i=1;i<=2*n;++i)
{
if(!dfn[i])
tarjan(i);
}
int pd=0;
for(int i=1;i<=n;++i)
{
if(kuai[i]==kuai[i+n])
{
pd=1;
break;
}
}
if(pd==0)
printf("GOOD\n");
else
printf("BAD\n");
}
return 0;
}