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
我也不知道为什么JSOI还有繁体字
这题可谓是2-SAT的模板题了,首先我们先来介绍一下2-SAT问题以及解法(附上百度文库的PPT)
简单的说,2-SAT问题就是有一些集合,每个集合中有且仅有两个元素,且不能同时选取两个元素,集合间的元素存在一定的选择关系,求解可行性及可行方案。
接下来说一个非常普通的2-SAT模型,比如有N组元素,其中每组都有x1i,x2i,每组中只能选一个元素,并且满足一些限定条件,比如x1i和x2j只能选一个,求最终是否有可行方案使每组都选。很明显,如果选了x1i,那么就不能选x2j。所以如果选了x1i,那就必选x1j,所以我们可以将x1i和x1j连边。我们通过这样的方式检出了图,然后对这张图进行缩点,如果x1i和x2i再同一个环里,则说明不可能有方案可行。这就是2-SAT的大致思路,具体证明可以在PPT里寻找。
那么我们回到这道题,题目中每种食品只能选满式或汉式中的一种,这很明显是2-SAT问题。然后题目给出条件两种食品必选一种。比如要求m1和h2中必有一种,那我们其实可以这样转化:如果选了h1,就必选h2(因为选了h1就不能选m1,但m1和h2必须有一个,所以只能选h2),同理如果选了m2,就必选m1。我们按照这样的必选关系建图,然后跑tarjan缩点,再进行判断,如果hi和mi属于同一个强连通分量,就输BAD,如果全部不存在矛盾就输GOOD即可。
#include<bits/stdc++.h>
#define MAXN 500
#define MAXM 500000
using namespace std;
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int k,n,m,cnt,top,tim,flag,co,head[MAXM],nxt[MAXM],to[MAXM];
int dfn[MAXN],low[MAXN],vis[MAXN],sta[MAXN],col[MAXN];
struct node{
int form1,form2,pl1,pl2;
}F[1005];
void add(int x,int y){
to[cnt]=y;nxt[cnt]=head[x];head[x]=cnt;cnt++;
}
void tarjan(int x){
dfn[x]=low[x]=++tim;
vis[x]=1;sta[++top]=x;
for(int i=head[x];i!=-1;i=nxt[i]){
if(!dfn[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
}
if(dfn[x]==low[x]){
int now=-1;co++;
while(now!=x){
now=sta[top--];
vis[now]=0;col[now]=co;
}
}
}
int main()
{
k=read();
while(k--){
flag=0;top=0;
memset(head,-1,sizeof(head));memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
n=read();m=read();
for(int i=1;i<=m;i++){
char c1,c2;
cin>>c1>>F[i].pl1>>c2>>F[i].pl2;
F[i].form1=c1=='h';F[i].form2=c2=='h';
}
for(int i=1;i<=n;i++)
for(int j=0;j<=1;j++)
for(int q=1;q<=m;q++){
if(F[q].pl1==i&&F[q].form1==j){
add((i-1)*2+j^1,(F[q].pl2-1)*2+F[q].form2);
add((F[q].pl2-1)*2+F[q].form2^1,(i-1)*2+j);
}
if(F[q].pl2==i&&F[q].form2==j){
add((i-1)*2+j^1,(F[q].pl1-1)*2+F[q].form1);
add((F[q].pl1-1)*2+F[q].form1^1,(i-1)*2+j);
}
}
for(int i=0;i<2*n;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
if(col[(i-1)*2]==col[(i-1)*2+1]){flag=1;break;}
if(flag) puts("BAD");else puts("GOOD");
}
return 0;
}
本文介绍了一次满汉全席烹饪大赛的背景及其与2-SAT问题的联系,通过分析大赛规则,将问题转化为2-SAT模型,并提供了解决方案。
1282

被折叠的 条评论
为什么被折叠?



