bzoj1823 [JSOI2010]满汉全席 2-sat

9 篇文章 0 订阅

Description


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

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

Solution


题目巨长题意巨水
很容易想到这是2-sat模型,那么根据不能同时选设两个点i和i‘,判断以下连边即可

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define rev(x) ((x<=n)?(x+n):(x-n))

const int N=2005;
const int E=40005;

struct edge {int x,y,next;} e[E];

int stack[N],dfn[N],low[N];
int bel[N];
int ls[N],top,edCnt;

bool vis[N];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
}

void dfs(int x) {
    dfn[x]=low[x]=++dfn[0];
    stack[++top]=x;
    vis[x]=true;
    for (int i=ls[x];i;i=e[i].next) {
        if (!dfn[e[i].y]) {
            dfs(e[i].y);
            low[x]=std:: min(low[x],low[e[i].y]);
        } else if (vis[e[i].y]) {
            low[x]=std:: min(low[x],dfn[e[i].y]);
        }
    }
    if (low[x]==dfn[x]) {
        bel[0]++;
        for (int tmp;tmp!=x;) {
            tmp=stack[top--];
            bel[tmp]=bel[0];
            vis[tmp]=0;
        }
    }
}

void tarjan(int n) {
    rep(i,1,2*n) dfn[i]=low[i]=vis[i]=0; dfn[0]=0;
    rep(i,1,2*n) if (!dfn[i]) dfs(i);
}

int main(void) {
    int T=read();
    while (T--) {
        fill(ls,0); edCnt=0;
        int n=read(),m=read();
        rep(i,1,m) {
            char s1=getchar(); for (;s1!='h'&&s1!='m';s1=getchar());
            int x=read();
            char s2=getchar(); for (;s2!='h'&&s2!='m';s2=getchar());
            int y=read();
            if (s1=='h') x=rev(x);
            if (s2=='h') y=rev(y);
            add_edge(x,rev(y));
            add_edge(y,rev(x));
        }
        tarjan(n);
        bool flag=true;
        rep(i,1,n) if (bel[i]==bel[rev(i)]) flag=false;
        if (flag) puts("GOOD");
        else puts("BAD");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值