JSOI2010 滿漢全席 【2-SAT】


傳送門:題目鏈接


滿漢全席

題目描述
滿漢全席是中國最豐盛的宴客菜餚,有許多種不同的材料透過滿族或是漢族的料理方式,呈現在數量繁多的菜色之中。由於菜色衆多而繁雜,只有極少數博學多聞技藝高超的廚師能夠做出滿漢全席,而能夠烹飪出經過專家認證的滿漢全席,也是中國廚師最大的榮譽之一。世界滿漢全席協會是由能夠料理滿漢全席的專家廚師們所組成,而他們之間還細分爲許多不同等級的廚師。

爲了招收新進的廚師進入世界滿漢全席協會,將於近日舉辦滿漢全席大賽,協會派遣許多會員當作評審員,爲的就是要在參賽的廚師之中,找到滿漢料理界的明日之星。

大會的規則如下:每位參賽的選手可以得到n 種材料,選手可以自由選擇用滿式或是漢式料理將材料當成菜餚。

大會的評審制度是:共有m 位評審員分別把關。每一位評審員對於滿漢全席有各自獨特的見解,但基本見解是,要有兩樣菜色作爲滿漢全席的標誌。如某評審認爲,如果沒有漢式東坡肉跟滿式的涮羊肉鍋,就不能算是滿漢全席。但避免過於有主見的審覈,大會規定一個評審員除非是在認爲必備的兩樣菜色都沒有做出來的狀況下,才能淘汰一位選手,否則不能淘汰一位參賽者。

換句話說,只要參賽者能在這兩種材料的做法中,其中一個符合評審的喜好即可通過該評審的審查。如材料有豬肉,羊肉和牛肉時,有四位評審員的喜好如下表:

評審一		 評審二 	評審三 		評審四 
滿式牛肉 	 滿式豬肉 	漢式牛肉 	漢式牛肉 
漢式豬肉 	 滿式羊肉 	漢式豬肉 	滿式羊肉

如參賽者甲做出滿式豬肉,滿式羊肉和滿式牛肉料理,他將無法滿足評審三的要求,無法通過評審。而參賽者乙做出漢式豬肉,滿式羊肉和滿式牛肉料理,就可以滿足所有評審的要求。

但大會後來發現,在這樣的制度下如果材料選擇跟派出的評審員沒有特別安排好的話,所有的參賽者最多隻能通過部分評審員的審查而不是全部,所以可能會發生沒有人通過考覈的情形。

如有四個評審員喜好如下表時,則不論參賽者採取什麼樣的做法,都不可能通過所有評審的考覈:

評審一 		評審二 		評審三 		評審四 
滿式羊肉 	滿式豬肉 	漢式羊肉 	漢式羊肉 
漢式豬肉 	滿式羊肉 	漢式豬肉 	滿式豬肉

所以大會希望有人能寫一個程序來判斷,所選出的m 位評審,會不會發生 沒有人能通過考覈的窘境,以便協會組織合適的評審團。

輸入描述:

第一行包含一個數字 K,代表測試文件包含了K 組資料。
每一組測試資料的第一行包含兩個數字n 跟m(n≤100,m≤1000),代表有n 種材料,m 位評審員。
爲方便起見,材料捨棄中文名稱而給予編號,編號分別從1 到n。
接下來的m 行,每行都代表對應的評審員所擁有的兩個喜好,每個喜好由一個英文字母跟一個數字代表,如m1 代表這個評審喜歡第1 個材料透過滿式料理做出來的菜,而h2 代表這個評審員喜歡第2 個材料透過漢式料理做出來的菜。
每個測試文件不會有超過50 組測試資料

輸出描述:

每筆測試資料輸出一行,如果不會發生沒有人能通過考覈的窘境,輸出GOOD;否則輸出BAD(大寫字母)。

示例1
輸入

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

輸出

GOOD
BAD



解題思路:

典型的 2-SAT 題,每種食物由 “滿” 和 “漢” 兩種做法,要通過一個評審的要求是至少滿足他的一個條件,那麼關係就是:如果其中一個條件沒有滿足那麼另外一個條件必須滿足。
而條件沒有滿足其實就是沒有做成他要求的做法,如:要求做 m3 ,那麼沒有滿足就是做成 h3 。


AC代碼:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#define ll long long 
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e3+10;

int k,n,m;
char s1[110],s2[110];
bool mark[2*N];
int stack[2*N];
int top;
vector<int> g[2*N];
void init()
{
    memset(mark,false,sizeof(mark));
    for(int i=0;i<2*N;i++)
        g[i].clear();
}
void addedge(int x,int y)
{
    g[x].push_back(y);
}
bool dfs(int x)
{
    if(mark[x^1]) return false;
    if(mark[x]) return true;
    mark[x]=true;
    stack[++top]=x;
    int len=g[x].size();
    for(int i=0;i<len;i++)
    {
        if(!dfs(g[x][i]))
            return false;
    }
    return true;
}
bool twosat()
{
    for(int i=0;i<2*n;i+=2)
    {
        if(!mark[i]&&!mark[i+1])
        {
            top=0;
            if(!dfs(i))
            {
                while(top>0)
                {
                    mark[stack[top--]]=false;
                }
                if(!dfs(i+1))
                    return false;
            }
        }
    }
    return true;
}


int main()
{
    char c1,c2;
    int a,b;
    scanf("%d",&k);
    while(k--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
        {
            cin>>c1>>a>>c2>>b;
            int aa=(c1=='h'),bb=(c2=='h');
            addedge((2*a+aa)^1,2*b+bb);
            addedge((2*b+bb)^1,2*a+aa);
        }
        if(twosat())
            printf("GOOD\n");
        else
            printf("BAD\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章