[BZOJ1823][JSOI2010]满汉全席
Description
你有\(n\)到菜要做,每道菜可以做成汉式或满式做法。有\(m\)评委,每个评委会指定两道菜(以及做法),要求你至少要做出其中的一道。问是否存在一组解满足所有评委的需求。
sol
直接\(2-sat\)啊。
为什么其他题解都写的是拆成\(4n\)个点的啊qaq
明明拆成\(2n\)个点就好了啊qaq
code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 205;
const int M = 2e3+5;
int T,n,m,to[M],nxt[M],head[N],cnt,dfn[N],low[N],tim,S[N],vis[N],bel[N],scc;
char a[10],b[10];
void link(int u,int v){
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void Tarjan(int u){
dfn[u]=low[u]=++cnt;
S[++S[0]]=u;vis[u]=1;
for (int e=head[u];e;e=nxt[e])
if (!dfn[to[e]]) Tarjan(to[e]),low[u]=min(low[u],low[to[e]]);
else if (vis[to[e]]) low[u]=min(low[u],dfn[to[e]]);
if (dfn[u]==low[u]){
++scc;int v;
do{
v=S[S[0]--];
bel[v]=scc;vis[v]=0;
}while (v!=u);
}
}
int main(){
T=gi();while (T--){
memset(head,0,sizeof(head));cnt=0;
memset(dfn,0,sizeof(dfn));scc=0;
n=gi();m=gi();
for (int i=1;i<=m;++i){
scanf("%s %s",a,b);
int u=0,v=0,j=1;
while (a[j]>='0'&&a[j]<='9') u=u*10+a[j]-'0',++j;
j=1;
while (b[j]>='0'&&b[j]<='9') v=v*10+b[j]-'0',++j;
link(u+n*(a[0]!='m'),v+n*(b[0]=='m'));
link(v+n*(b[0]!='m'),u+n*(a[0]=='m'));
}
for (int i=1;i<=2*n;++i) if (!dfn[i]) Tarjan(i);
int ans=1;
for (int i=1;i<=n;++i) ans&=(bel[i]!=bel[i+n]);
puts(ans?"GOOD":"BAD");
}
return 0;
}