BZOJ 1823 满汉全席

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1823


大意:

1823: [JSOI2010]满汉全席

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 2930   Solved: 1417
[ Submit][ Status][ Discuss]

Description

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

Input

第一行包含一个数字 K,代表测试文件包含了K 组资料。每一组测试资料的第一行包含兩个数字n 跟m(n≤100,m≤1000),代表有n 种材料,m 位评审员。为方便起見,材料舍弃中文名称而给予编号,编号分别从1 到n。接下來的m 行,每行都代表对应的评审员所拥有的兩个喜好,每个喜好由一个英文字母跟一个数字代表,如m1 代表这个评审喜欢第1 个材料透过满式料理做出來的菜,而h2 代表这个评审员喜欢第2 个材料透过汉式料理做出來的菜。每个测试文件不会有超过50 组测试资料

Output

每笔测试资料输出一行,如果不会发生没有人能通过考核的窘境,输出GOOD;否则输出BAD(大写字母)。

Sample Input

2
3 4
m3 h1
m1 m2
h1 h3
h3 m2
2 4
h1 m2
m2 m1
h1 h2
m1 h2

Sample Output

GOOD
BAD


sol:

2-SAT :

  • 考虑条件 a∪b  =>  ¬a->b && ¬b->a
  • 将n个选值编号为1~n 则对任意结点a对应编号i , 其否结点¬a编号为i+n
  • 根据上述情况连边并进行强联通缩点
  • 若存在a与¬a 在同一强联通分支中,不存在方案
  • 若sno[i]>sno[i+n],则选取i,否则选择¬i


code:

#include<bits/stdc++.h>

using namespace std;

#define pb push_back

const int maxn = 1e3+5;
const int inf = 0x3f3f3f3f;
typedef long long ll;

int n,m;

vector<int> G[maxn];
vector<int> rG[maxn];
vector<int> vs;

bool vis[maxn];
int sno[maxn];
int tot=0;

//顺序dfs
void dfs(int u){
    vis[u]=true;
    for(int i=0;i<G[u].size();i++){
        if(!vis[G[u][i]]) dfs(G[u][i]);
    }
    vs.push_back(u);
}

//逆图dfs
void rdfs(int u,int no){
    vis[u]=true;
    sno[u]=no;
    for(int i=0;i<rG[u].size();i++){
        int v=rG[u][i];
        if(!vis[v]) rdfs(v,no);
    }
}

//分解强联通分量
void find_scc(){
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++){
        if(!vis[i]) dfs(i);
    }
    memset(vis,false,sizeof(vis));
    for(int i=vs.size()-1;i>=0;i--){
        if(!vis[vs[i]]) rdfs(vs[i],++tot);
    }
}

void init(){
    for(int i=0;i<=2*n;i++) {
        G[i].clear();
        rG[i].clear();
    }
    tot=0;
}

// 求u的否
int rev(int u){
    return u<=n?u+n:u-n;
}

//对于
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init();
        while(m--){
            getchar();
            char c=getchar();
            int x,y;
            scanf("%d",&x);     if(c=='m') x+=n;
            getchar();          c=getchar();
            scanf("%d",&y);     if(c=='m') y+=n;
            G[rev(x)].push_back(y);
            G[rev(y)].push_back(x);
            rG[y].push_back(rev(x));
            rG[x].push_back(rev(y));
        }
        find_scc();
        bool flag=true;
        for(int i=1;i<=n;i++){
            if(sno[i]==sno[i+n]) {
                flag=false;
                break;
            }
        }
        if(flag) printf("GOOD\n");
        else printf("BAD\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值