[BZOJ1823][JSOI2010]满汉全席

bzoj
luogu

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;
}
posted @ 2018-05-28 22:31  租酥雨  阅读(184)  评论(0编辑  收藏  举报