你准备为你和朋友订一个比萨,他们告诉你每个人希望比萨里有什么和没有什么材料。当然,他们也明白只有一个比萨,所以没有人期望他所以的要求都得到满足。你订一个比萨满足他们每个人至少一项的要求吗?
比萨店提供的比萨口味如下,你可以在一个比萨中要或者不要当中的任何一项:
|
代码
|
口味
|
|
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.");
}

setup()
4038

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



