如何在没有排列的情况下编写findall?

时间:2017-01-11 19:50:27

标签: prolog

我想写一个评估的程序,哪个项目组合可以在特定的行李容量中携带。该计划的重要部分是推出所有可能性的排列。该计划应该给出一次可能性,而不是它们的排列。这是一个示例查询:

?- place(Possibility, 2).
Possibility = [water];
Possibility = [flower];
Possibility = [paper];
Possibility = [meat];
Possibility = [wood];
Possibility = [glass];
Possibility = [water, flower];
Possibility = [water, paper];
Possibility = [flower, paper].

到目前为止我的代码是:

% item(Name, Space)
item(water, 1).
item(flower, 1).
item(paper, 1).
item(meat, 2).
item(wood, 2).
item(glass, 2).
item(stone, 3).
item(gold, 3).
item(metal, 3).
item(platin, 4).

% maximum capacity of bag
maxcapacity(10).

place(Possibility, Capacity) :-
    maxcapacity(MaxCapacity),
    between(1, MaxCapacity, Capacity),
    possibilities(Capacity, [], Possibility).

possibilities(Capacity, Acc, Acc) :-
    \+ (space(Possibility, [], 0, Capacity), sort(Possibility, SortedPossibility), \+ member(SortedPossibility, Acc)).
possibilities(Capacity, Acc, PossibilityList) :-
    space(Possibility, [], 0, Capacity),
    sort(Possibility, SortedPossibility),
    not(member(SortedPossibility, Acc)),
    Acc1 = [SortedPossibility|Acc],
    possibilities(Capacity, Acc1,PossibilityList).

space(Acc, Acc, Space, MaxCapacity) :-             
    Space =< MaxCapacity,
    Acc \= [].
space(Possibility, Acc, Space, MaxCapacity) :-
    item(Item, ItemSpace),
    not(member(Item, Acc)),
    NewSpace is Space + ItemSpace,
    NewSpace =< MaxCapacity,
    Acc1 = [Item|Acc],
    space(Possibility, Acc1, NewSpace, MaxCapacity).

我尝试通过排序来排除排列,但程序仍然给了我所有的排列,并将项目组合以某种方式放在列表中。程序应该像上面的示例查询一样工作。

我真的很感激任何帮助!

2 个答案:

答案 0 :(得分:1)

您已经使用space/4谓词进行了大部分操作,但随后您在possibilities/3中添加了额外内容,其中&#34;将项目组合以某种方式放入列表中#34;虽然你不想要那个。

因此,让我们直接看一下space/4的例子:

?- space(Possibility, [], 0, 2).
Possibility = [water] ;
Possibility = [flower, water] ;
Possibility = [paper, water] ;
Possibility = [flower] ;
Possibility = [water, flower] ;
Possibility = [paper, flower] ;
Possibility = [paper] ;
Possibility = [water, paper] ;
Possibility = [flower, paper] ;
Possibility = [meat] ;
Possibility = [wood] ;
Possibility = [glass] ;
false.

请注意,您获得了容量1的解决方案以及容量2的解决方案。您使用maxcapacity/1between/3向我建议您想要解决方案容量正好 2。您可以在=<的第一个条款中将=更改为space/4以获取此信息:

?- space(Possibility, [], 0, 2).
Possibility = [flower, water] ;
Possibility = [paper, water] ;
Possibility = [water, flower] ;
Possibility = [paper, flower] ;
Possibility = [water, paper] ;
Possibility = [flower, paper] ;
Possibility = [meat] ;
Possibility = [wood] ;
Possibility = [glass] ;
false.

现在我们可以单独消除每个解决方案中的排列,而不是像你一样,在列表中收集所有解决方案并尝试使用它,这更难

消除不需要的排列意味着选择代表性排列并忽略所有其他排列。例如,我们可以选择严格增加(即按字母顺序排列)的排列作为代表:

?- space(Possibility, [], 0, 2), increasing(Possibility).
Possibility = [flower, water] ;
Possibility = [paper, water] ;
Possibility = [flower, paper] ;
Possibility = [meat] ;
Possibility = [wood] ;
Possibility = [glass] ;
false.

increasing/1谓词可以定义如下:

increasing([]).
increasing([_]).
increasing([X,Y|Xs]) :-
    X @< Y,
    increasing([Y|Xs]).

有了这个,您可以丢弃possibilities/3谓词,并将上面的查询概括为您place/2的定义。

答案 1 :(得分:1)

您的问题是您的程序正在创建可能性列表,而不是可能性。相反,下面的代码找到了可能性,然后回溯以找到下一个可能性。

possibilities(_, Current, Current)将当前工作可能性与查询统一起来,以返回当前可能性。 Current \= []用于消除空袋(根据您的预期结果)。

回溯后,possibilities(Capacity, [], Possibility)用于查找包中的初始元素。将选择适合包中的第一个项目,我们递归(首先是上面的统一条款,然后是下面的部分完整的包子句)。一旦所有可能性都已经用尽了这个项目,我们回溯并找到适合的下一个项目。

possibilities(Capacity, [Current|Rest], Possibility)基本上以与possibilities(Capacity, [], Possibility)相同的方式运行,但需要进行一次额外的检查,以确保我们只能按字母顺序获取可能性,以消除排列。然后按上述方式递归。

(作为旁注,如果您希望能够将两个水储存在行李中,只需将A @< Current更改为A @=< Current)。

item(water, 1).
item(flower, 1).
item(paper, 1).
item(meat, 2).
item(wood, 2).
item(glass, 2).
item(stone, 3).
item(gold, 3).
item(metal, 3).
item(platin, 4).

% maximum capacity of bag
maxcapacity(10).

place(Possibility, Capacity) :-
    maxcapacity(MaxCapacity),
    between(1, MaxCapacity, Capacity),
    possibilities(Capacity, [], Possibility).

possibilities(_, Current, Current) :- 
    Current \= [].

possibilities(Capacity, [], Possibility) :-
    item(A, B),
    B =< Capacity,
    NewCapacity is Capacity - B,
    possibilities(NewCapacity, [A], Possibility).

possibilities(Capacity, [Current|Rest], Possibility) :-
    item(A, B),
    B =< Capacity,
    NewCapacity is Capacity - B,
    A @< Current,
    possibilities(NewCapacity, [A,Current|Rest], Possibility).