51nod_2861 满汉全席(2-SAT)

满汉全席

Problem 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

样例输入1:
1
3 4
m3 h1
m1 m2
h1 h3
h3 m2
样例输入2:
1
2 4
h1 m2
m2 m1
h1 h2
m1 h2
样例输入3:
2
3 4
m3 h1
m1 m2
h1 h3
h3 m2
2 4
h1 m2
m2 m1
h1 h2
m1 h2

Sample Output

样例输出1:
GOOD
样例输出2:
BAD
样例输出3:
GOOD
BAD

题解:

m个评委,每个评委有两种喜爱的菜式,至少满足一个即可。将n个菜品,每个分为两个点,一个点代表汉式做法,一个点代表满式做法。对于评委喜欢的菜式,设为ax by样式, a , b ∈ { h , m } , 1 ≤ x , y ≤ n a,b\in\{h,m\}, 1\le x,y \le n a,b{h,m},1x,yn。例 h 2 m 3 h2 m3 h2m3,若做了m2,则必须做m3,若做了h3,必须做m2,这样连两条边 ( m 2 − > m 3 ) , ( h 3 − > h 3 ) (m2->m3), (h3->h3) (m2>m3),(h3>h3)
建完图后,求强连通分量,若hx和mx在同一强连通分量内,则无合理方案。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-7
 
using namespace std;
typedef long long LL;   
typedef pair<LL, int> P;
const int maxn = 2020;
const int mod = 998244353;
int cnt, sum, top, dfn[maxn], low[maxn], col[maxn], st[maxn], vis[maxn];
vector<int> g[maxn];
void init();
void trajan(int u);

int main()
{
    int t, n, m, i, j, k;
    char ch1, ch2;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d", &n, &m);
        for(i=1;i<=2*n;i++)g[i].clear();
        for(i=1;i<=m;i++){
            scanf(" %c%d %c%d", &ch1, &j, &ch2, &k);
            if(j != k){
                int j1, j2, k1, k2;
                if(ch1 == 'h')j1 = 2*j-1, j2=2*j;
                else j1 = 2*j, j2 = 2*j-1;
                if(ch2 == 'h')k1 = 2*k-1, k2 = 2*k;
                else k1 = 2*k, k2 = 2*k-1;
                g[j2].push_back(k1);
                g[k2].push_back(j1); 
            }else if(ch1 == ch2 && j == k){
                int j1, j2;
                if(ch1 == 'h')j1 = 2*j-1, j2 = 2*j;
                else j1 = 2*j, j2 = 2*j-1;
                g[j2].push_back(j1);
            }
        }
        init();
        for(i=1;i<=2*n;i++)
            if(dfn[i] == -1)trajan(i);
        int sig = 1;
        for(i=1;i<=n;i++)
            if(col[2*i] == col[2*i-1])
                sig = 0;
        if(sig)printf("GOOD\n");
        else printf("BAD\n");
    }
    return 0;
}

void init()
{
    memset(dfn, -1, sizeof(dfn));
    sum = top = 0;
    memset(vis, 0, sizeof(vis));
}

void trajan(int u)
{
    dfn[u] = low[u] = cnt++;
    st[++top] = u;
    vis[u] = 1;
    for(int i=0;i<g[u].size();i++)
    {
        int v = g[u][i];
        if(dfn[v] == -1){
            trajan(v);
            low[u] = min(low[u], low[v]);
        }else if(vis[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]){
        sum++;
        col[u] = sum;
        vis[u] = 0;
        while(top && st[top] != u){
            col[st[top]] = sum;
            vis[st[top]] = 0;
            top--;
        }
        top--;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值