大衆比薩

 
你準備爲你和朋友訂一個比薩,他們告訴你每個人希望比薩里有什麼和沒有什麼材料。當然,他們也明白只有一個比薩,所以沒有人期望他所以的要求都得到滿足。你訂一個比薩滿足他們每個人至少一項的要求嗎?
比薩店提供的比薩口味如下,你可以在一個比薩中要或者不要當中的任何一項:
代碼
口味
A
鳳尾魚
B
黑橄欖
C
加拿大燻肉
D
方丁大蒜
E
濃奶酪
F
鮮花椰菜
G
青辣椒
H
火腿
I
意大利香腸
J
加拉佩諾胡椒
K
波蘭薰腸
L
瘦牛肉
M
蘑菇
N
脫脂羊乳酪
O
洋蔥
P
胡椒
 
你的朋友給你一行文字描述他們的比薩口味。例如:
+O-H+P;
意味這某位朋友將接受一個包含洋蔥,或不包含火腿,或帶有胡椒的比薩。而
-E-I-D+A+J;
表示某位朋友將接受一個不包含濃奶酪或意大利香腸或方丁大蒜的,或帶有鳳尾魚或加拉佩諾胡椒的比薩。
輸入格式:
每個要求一行,並以分號結束。直到“.”表示所有約束都已輸入結束。
輸出格式:
如果存在可分配的方案則先輸出一個長度爲10 的字符串“Toppings: ”,緊接輸出分配方案(按字母順序由小到大)。
如果不存在可分配的方案則輸出:“No pizza can satisfy these requests.”
輸入輸出樣例:
Simple input 1
Output for the input
+A+B+C+D-E-F-G-H;
-A-B+C+D-E-F+G+H;
-A+B-C+D-E+F-G+H;
.
Toppings:
 
Simple input 2
Output for the input
+A+B+C+D;
+E+F+F+H;
+A+B-G;
+O+J-F;
+H+I+C;
+P;
+O+M+L;
+M-L+P;
.
 
Toppings: CELP
 
Simple input 3
Output for the input
+A;
-A;
.
 
No pizza can satisfy these requests.
 
解:
本題有兩種解法:第一種比較複雜:首先將每個人的口味約束表示乘析取式,如+A -B+C表示成(A | !b | C),接着將所有人的口味表示成合取式,如+A+B和+C -D表示成( A | B ) & (C | !D),在將合取式中所有的括號展開變成析取式,這時使任意析取式爲真的表達式都是問題的解,如(A & B)| (C &!D) 表示當A、B同時取真,或者C取真D取假時都是問題的解。
第二種方法是使用搜索算法,窮舉所有的可能性,直到找到解爲止。
儘管這種方法沒有第一種那麼聰明,但是由於實現起來比第一種簡單的多,所以在這裏採用搜索算法更科學些。
使用搜索算法時還要注意的兩個問題是:1、比薩約束的存儲方式;2、如何判斷比薩是否符合要求。
這裏使用位運算來表示比薩的約束方式:定義一個整形數組want[ PERSONMAX],其中PERSONMAX表示朋友的個數,want[ i ]表示第i 爲朋友想要的口味,例如:
want[ i ]=00000000000000000000000001000011 表示第i個朋友想要口味鳳尾魚、黑橄欖和青辣椒。注意由於整形有32位而pizza的口味只有16種,所以這裏高16爲無效。
同理,定義另一個整形數組hate[PERSONMAX],hate[i]表示第i位朋友不想要的口味,例如:
hate[ i ]=00000000000000000000000000001100 表示第i個朋友不想要的口味有:方丁大蒜和加拿大燻肉。
於是在表述pizza是否符合某人的口味是隻要進行如下判斷:
(pizza & want[ i ] >0) ||(!pizza & hate[ i ] >0)
這種表示方法充分利用了位運算的優點,使得程序的處理十分的方便,而且節省了空間.
 
代碼:
 
 
#include<stdio.h>
#include
<string.h>
#include
<stdlib.h>
#include
<fcntl.h>
#include
<io.h>


#define TYPELEN 16    //比薩口味的種類數
#define PERSONMAX 30 //最多的朋友人數

int pizza,want[PERSONMAX],hate[PERSONMAX],person;
char buf[TYPELEN*2];

void
setup()
{
    
int count,i;
    count
=strlen(buf)-1;    //最後一個是分號,因捨去。
    memset(want+person,0,TYPELEN);    
    memset(hate
+person,0,TYPELEN);
    
for(i=1;i<count;i+=2)
        
if(buf[i-1]=='+')
            want[person]
=want[person]|(1<<(buf[i]-65));
        
else
            hate[person]
=hate[person]|(1<<(buf[i]-65));
    
++person;
}


bool 
checkPizza()
{
    
bool flag;
    
int i;
    
for(pizza=0;pizza<65536;pizza++){    //搜索所有的可能pizza取值,直到成功
        flag=true;
        
for(i=0;i<person;i++)
            
if(!((pizza&want[i])>0 || (!pizza&hate[i])>0)){
                flag
=false;
                
break;
            }

        
if(flag) return true;
    }

    
return false;
}

void
output(){
 int i;
 printf("Toppings: ");
 for(i=0;i<TYPELEN;i++)
  if(pizza&(1<<i)) putchar(i+65);
 puts("/0");
}

void
main(){
 person=0;
 while(1){
  scanf("%s",buf);
  if(buf[0]=='.') break;
  setup();
 }
 if(checkPizza()==true) output();
 else puts("No pizza can satisfy these requests."); 
}

 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章