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

猜你喜欢

转载自www.cnblogs.com/zhoushuyu/p/9102686.html