[BZOJ 1823][JSOI2010]满汉全席(2-SAT)

Description

满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中。由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉全席,而能够烹饪出经过专家认证的满汉全席,也是中国厨师最大的荣誉之一。 世界满汉全席协会是由能够料理满汉全席的专家厨师们所组成,而他们之间还细分为许多不同等级的厨师。为了招收新进的厨师进入世界满汉全席协会,将于近日举办满汉全席大赛,协会派遣许多会员当作评审员,为的就是要在參赛的厨师之中,找到满汉料理界的明日之星。 大会的规则如下:每位參赛的选手可以得到n 种材料,选手可以自由选择用满式或是汉式料理将材料当成菜肴。大会的评审制度是:共有m 位评审员分别把关。每一位评审员对于满汉全席有各自独特的見解,但基本见解是,要有兩样菜色作为满汉全席的标志。如某评审认为,如果没有汉式东坡肉跟满式的涮羊肉锅,就不能算是满汉全席。但避免过于有主見的审核,大会规定一个评审员除非是在认为必备的两样菜色都没有做出來的狀况下,才能淘汰一位选手,否则不能淘汰一位參赛者。换句话說,只要參赛者能在这兩种材料的做法中,其中一个符合评审的喜好即可通过该评审的审查。如材料有猪肉,羊肉和牛肉时,有四位评审员的喜好如下表: 评审一 评审二 评审三 评审四 满式牛肉 满式猪肉 汉式牛肉 汉式牛肉 汉式猪肉 满式羊肉 汉式猪肉 满式羊肉 如參赛者甲做出满式猪肉,满式羊肉和满式牛肉料理,他将无法满足评审三的要求,无法通过评审。而參赛者乙做出汉式猪肉,满式羊肉和满式牛肉料理,就可以满足所有评审的要求。 但大会后來发现,在这样的制度下如果材料选择跟派出的评审员没有特别安排好的话,所有的參赛者最多只能通过部分评审员的审查而不是全部,所以可能会发生没有人通过考核的情形。如有四个评审员喜好如下表时,则不論參赛者采取什么样的做法,都不可能通过所有评审的考核: 评审一 评审二 评审三 评审四 满式羊肉 满式猪肉 汉式羊肉 汉式羊肉 汉式猪肉 满式羊肉 汉式猪肉 满式猪肉 所以大会希望有人能写一个程序來判断,所选出的m 位评审,会不会发生没有人能通过考核的窘境,以便协会组织合适的评审团。

Solution

2-SAT模板题

一个点拆成2i和2i+1,分别表示真和假。对“xi为真或者xj为真”这样的条件,连一条有向边2i+1->2j,表示当xi为假时,xj一定要为真。同理连一条2j+1->2i,表示xj为假时,xi要为真。每个条件对应两条“对称”的边。接下来考虑每个没有被赋值的变量,设为xi。我们先假定他为真,标识2i,并沿着有向边标识所有能标识的点,如果标识过程中发现某个变量对应的两个点都被标识了,说明“xi为真”这个假设不成立,需要改为‘xi为假’,然后重新标识,若还是不成立,则这个2-sat问题无解。

——刘汝佳

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
int K,n,m,c,s[305];
bool dishes[305];
vector<int>G[305];
int read()
{
    int x=0,f=1;char c=getchar();
    while(c!='m'&&c!='h')c=getchar();
    f=(c=='m')?0:1;c=getchar();
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';c=getchar(); 
    }
    return x*2+f;
}
bool dfs(int u)
{
    if(dishes[u])return true;
    if(dishes[u^1])return false;
    s[c++]=u;
    dishes[u]=1;
    for(int i=0;i<G[u].size();i++)
    if(!dfs(G[u][i]))return false;
    return true;
}
bool work()
{
    for(int i=1;i<=n;i++)
    {
        if(!dishes[i*2]&&!dishes[i*2+1])
        {
            c=0;
            if(!dfs(i*2)){
                while(c)dishes[s[c-1]]=0,c--;
                if(!dfs(i*2+1))return false;
            }
        }
    }
    return true;
}
int main()
{
    scanf("%d",&K);
    while(K--) 
    {
        scanf("%d%d",&n,&m);
        memset(dishes,0,sizeof(dishes));
        for(int i=0;i<(n+1)*2;i++)
        G[i].clear(); 
        for(int i=1;i<=m;i++)
        {
            int u=read(),v=read();
            G[u^1].push_back(v);
            G[v^1].push_back(u);
        }
        if(work())printf("GOOD\n");
        else printf("BAD\n");
    }
    return 0;
} 

 

posted @ 2017-04-21 19:35  Zars19  阅读(200)  评论(0编辑  收藏  举报