题目传送门:【BZOJ 1823】
题目大意: ……为了招收新进的厨师进入世界满汉全席协会,近日该协会将举办满汉全席大赛。协会将派遣许多会员当作评委,为的就是要在参赛的厨师之中,找到满汉料理界的明日之星。每位参赛的选手可以得到 n 种菜品材料,选手可以自由选择用满式或是汉式料理将该材料当成菜肴。共有 m 位评审员分别把关,每一位评审员都有两种喜欢的菜品种类。只要参赛者能在评审员所喜爱的两种菜品中,做出任意一个符合评审喜好的菜品即可通过该评委的审查。但大会后来发现,在这样的制度下如果材料选择跟派出的评审员没有特别安排好的话,所有的参赛者最多只能通过部分评委的审查而不是全部,所以可能会发生没有人通过考核的情形。所以大会希望你能写一个程序来判断,所选出的 m 位评审,会不会发生没有人通过考核的窘境,以便协会组织合适的评审团。
输入共 K 组数据,每组数据第一行为两个整数 n , m,代表有 n 种菜品,m 位评审员(K ≤ 50 , n ≤ 100 , m ≤ 1000)。接下来的 m 行,每行都代表对应的评审员所拥有的两个喜好菜品,每个喜好菜品由一个英文字母跟一个数字代表(例如:m1 , h2)。每组数据输出一行,如果不会发生没有人通过考核的窘境,输出 GOOD;否则输出BAD(大写字母)。
题目分析:
一道 2-SAT 的模板题。想必看明白了 2-SAT 算法的同学在认真读完这道题之后就应该能想到吧。
对于每一种菜品,我们把它拆成两个点 h 和 m,代表它是被做成汉式菜或者是满式菜。显然一种菜品只能有一种选择。然后对于输入中给出的关系,由于两种菜品(A , B)中至少需要选择一个,所以我们建立(A’ -> B),(B’ -> A)两条边表示两种菜品至少要有一种满足评审员的喜好风格。之后按照常规跑 2-SAT 即可。
下面附上代码:
- #include<cstdio>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #include<stack>
- using namespace std;
- const int MXN = 105,MXM = 1005;
- struct Edge{
- int to,next;
- };
- Edge edge[MXN * MXN * 2];
- int n,m,head[MXN * 2],now = 0;
- int dfn[MXN * 2],low[MXN * 2],cnt = 0,_index = 0,belong[MXN * 2];
- stack<int> s;
- bool ins[MXN * 2];
- int istype_Man(int c){ //判断这个菜是否为满式菜
- if (c == ‘m’ || c == ‘M’) return 1; //在之后建边的时候使用
- return 0;
- }
- void adde(int u,int v){
- edge[++now].to = v;
- edge[now].next = head[u];
- head[u] = now;
- }
- void tarjan(int u){
- dfn[u] = low[u] = ++_index;
- s.push(u);
- ins[u] = true;
- for (int i = head[u];i;i = edge[i].next){
- int v = edge[i].to;
- if (!dfn[v]){
- tarjan(v);
- if (low[v] < low[u])
- low[u] = low[v];
- } else if (ins[v] && dfn[v] < low[u])
- low[u] = dfn[v];
- }
- if (dfn[u] == low[u]){
- ++cnt;
- int tmp;
- do {
- tmp = s.top();
- s.pop();
- belong[tmp] = cnt;
- ins[tmp] = false;
- }while (tmp != u);
- }
- }
- void _init(){
- memset(belong,0,sizeof(belong));
- memset(dfn,0,sizeof(dfn));
- memset(low,0,sizeof(low));
- memset(edge,0,sizeof(edge));
- memset(head,0,sizeof(head));
- now = 0,cnt = 0,_index = 0;
- }
- int main(){
- int T,a,b; //a,b:菜品材料编号
- char type1,type2; //type1,type2:对应的族系(汉 / 满)
- cin>>T;
- while (T–){
- cin>>n>>m;
- for (int i = 1;i <= m;i++){
- cin>>type1>>a>>type2>>b;
- //scanf(“%c%d %c%d”,&type1,&a,&type2,&b);
- if (a>b) swap(type1,type2),swap(a,b);
- a += istype_Man(type1) * n;
- b += istype_Man(type2) * n;
- if (a <= n) adde(a + n,b);
- else adde(a - n,b);
- if (b <= n) adde(b + n,a);
- else adde(b - n,a);
- }
- for (int i = 1;i <= 2 * n;i++){
- if (!dfn[i]) tarjan(i);
- }
- bool reach = false;
- for (int i = 1;i <= n;i++){
- if (belong[i] == belong[i + n]){
- reach = true;
- break;
- }
- }
- if (!reach) printf(“GOOD\n”);
- else printf(“BAD\n”);
- _init();
- }
- return 0;
- }