BZOJ-1823: [JSOI2010]满汉全席

[文章目录]

Description

有n种材料,m个评审员,每个评审员有两个要求,至少满足其中一个即可通过评审。要求类似第x道菜需要通过满/汉式做出来。询问能否有一种方案来做n种材料,使得通过全部评审员。多组数据<=50 n<=100 m<=1000

2-sat。
对于每个材料建两个点表示两种选择,对于一个限定a1或b2,我们连边a2->b2 b1->a1,表示如果a选择了1,那么b必须选择2,如果b选择了1,a必须选择1。建造的图中没有任何两点x1,x2相互可达即有解。
两种算法:
1.对于每对点中的一个进行搜索,标记种类,如果不合法,更换为另一个。如果都不合法即无解。时间复杂度O(nm)
2.tarjan原图,枚举点对,都不在一个强连通分量中即有解。复杂度O(m)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read()
{
    char ch=getchar();
    while(ch!=EOF&&ch!='m'&&ch!='h') ch=getchar();
    return ch=='h';
}
int n,m;
int head[300],to[2100],nxt[2100],cnt;
inline void add(int x,int y)
{
    to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt;
}
int dfn[300],low[300],tim,z[300],top,bel[300],bs;
bool inz[300];
void tarjan(int x)
{
    low[x]=dfn[x]=++tim; z[++top]=x; inz[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        if(!dfn[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
        else if(inz[to[i]]) low[x]=min(low[x],dfn[to[i]]);
    }
    if(low[x]==dfn[x])
    {
        int t; bs++;
        do
        {
            t=z[top--];
            inz[t]=0;
            bel[t]=bs;
        }while(t!=x);
    }
}
int main()
{
    int t; scanf("%d",&t);
    while(t--)
    {
        memset(head,0,sizeof head); cnt=0;
        memset(dfn,0,sizeof dfn); tim=bs=0;
        scanf("%d%d",&n,&m);
        int fl1,fl2,a,b;
        while(m--)
        {
            fl1=read(); scanf("%d",&a);
            fl2=read(); scanf("%d",&b);
            add((a<<1)|(fl1^1),(b<<1)|fl2);
            add((b<<1)|(fl2^1),(a<<1)|fl1);
        }
        for(int i=2;i<=2*n+1;++i) if(!dfn[i]) tarjan(i);
        fl1=1;
        for(int i=1;i<=n;++i) if(bel[i<<1]==bel[i<<1|1]) fl1=0;
        if(fl1) puts("GOOD");
        else puts("BAD");
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注