印刷名片 - 一种背包任务

时间:2012-01-08 16:22:20

标签: prolog

我是Prolog的新手,我对一段代码有一些简单的问题。这是上周五出现的现实世界问题,并且相信我这不是CS家庭作业。

我们要打印名片,这些名片只能以900张卡片打印(100张,每张9张卡片)。任何人的牌都不应分布在几个街区。人们订购了不同数量的卡片,E.G:

% "braucht" is german and means "needs"
braucht(anton,400).
braucht(berta,200).
braucht(claudia,400).
braucht(dorothee,100).
braucht(edgar,200).
braucht(frank,400).
braucht(georg,100).

我将以下定义放在一起,以找到900张名片的适当块:

block(0,[]).
block(N,[H|T]) :-
    braucht(H,Nh),
%   \+(member(H,T)),
    D is N - Nh,
    D >= 0,
    block(D,T).

这会产生一个很好的人群列表,这些人的卡片在900卡块上组合在一起。但是如果我激活注释行“\ + member ....”并且只给我一个“假”,它就会停止工作。但我需要确保没有人在这个街区上不止一次。我在这里做错了什么?

2 个答案:

答案 0 :(得分:3)

您希望实现的目标是设置H未出现在列表尾T中的约束。但是,当您致电T时,member/2仍然未绑定,因此member(H, T)将成功,因此\+ member(H,T)将失败。

如果您不想使用Constraint Programming,而是使用纯Prolog,则应该使用另一个方向的检查并检查已汇总的人员列表中是否已存在H到那时。类似的东西:

block(0, List, List).
block(N, Rest, List) :-
  braucht(H, Nh),
  \+(memberchk(H, Rest)), % will fail when H is already in Rest
  D is N-Nh,
  D >= 0,
  block(D, [H|Rest], List).

可以从谓词block/3调用谓词block/2

block(N, List) :-
  block(N, [], List).

答案 1 :(得分:2)

如果块谓词中的第二个参数是“输出”,那么问题是T是一个自由变量,因此成员(_,T)将始终成功。例如:

?- member(anton,T).

T = [anton|_]
T = [_,anton|_]
T = [_,_,anton|_]

依旧......