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

Prolog 如何在没有排列的情况下编写findall?,prolog,Prolog,我想写一个程序来评估,在一个特定的行李容量内可以携带哪些物品组合。该计划的重要部分是排除所有可能的排列。程序应该给出每种可能性一次,而不是它们的排列。下面是一个查询示例: ?- place(Possibility, 2). Possibility = [water]; Possibility = [flower]; Possibility = [paper]; Possibility = [meat]; Possibility = [wood]; Possibility = [glass]; P

我想写一个程序来评估,在一个特定的行李容量内可以携带哪些物品组合。该计划的重要部分是排除所有可能的排列。程序应该给出每种可能性一次,而不是它们的排列。下面是一个查询示例:

?- 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).
%项(名称、空格)
项目(水,1)。
项目(花卉,1)。
项目(文件,1)。
项目(肉,2)。
项目(木材,2)。
项目(玻璃,2)。
项目(石头,3)。
项目(黄金,3)。
项目(金属,3)。
项目(铂,4)。
%行李最大容量
最大容量(10)。
地点(可能性、容量):-
最大容量(maxcapacity),
介于(1,最大容量,容量),
可能性(容量,[],可能性)。
可能性(容量、Acc、Acc):-
\+(空间(可能性,[],0,容量),排序(可能性,排序可能性),\+成员(排序可能性,Acc))。
可能性(容量、Acc、可能性列表):-
空间(可能性,[],0,容量),
排序(可能性、排序可能性),
非(成员(分类可能性,Acc)),
Acc1=[SortedPossibility | Acc],
可能性(容量、Acc1、可能性列表)。
空间(Acc、Acc、空间、最大容量):-
空间=<最大容量,
Acc\=[]。
空间(可能性、Acc、空间、最大容量):-
项目(项目,项目空间),
非(成员(项目,Acc)),
新闻空间是空间+项目空间,
新闻空间=
我试图通过排序排除排列,但程序仍然给我所有排列,并以某种方式将项目组合放入列表中。该程序应该像上面的示例查询一样工作


我真的很感激任何帮助

您已经用
空格/4
谓词完成了大部分操作,但随后您在
可能性/3
中添加了额外的内容,这会“以某种方式将项目组合放入列表”,尽管您不希望这样做

让我们直接看一下
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/1
between/3
向我表明,您在这里只需要容量正好为2的解决方案。您可以使用
空格/4
谓词更改
=您已经完成的大部分操作,但是您可以在
可能性/3
中添加额外的内容,这会“以某种方式将项目组合放入列表”,尽管您不希望这样

让我们直接看一下
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/1
between/3
向我表明,您在这里只需要容量正好为2的解决方案。您可以更改
=您的问题是您的程序正在创建可能性列表,而不是可能性。下面的代码找到了一种可能性,然后回溯到下一种可能性

可能性(u,Current,Current)
将当前工作可能性与查询统一,以返回当前可能性作为结果<代码>当前\=[]
用于消除空包的可能性(基于您的预期结果)

回溯后,
可能性(容量,[],可能性)
用于查找行李中的初始元素。将选择适合装入袋子的第一个项目,然后我们重复(首先是上面的统一条款,然后是下面的部分装满袋子条款)。一旦袋子里的这件物品用尽了所有的可能,我们回过头来寻找下一件合适的物品

可能性(容量,[Current | Rest],可能性)
基本上以与
可能性(容量,[],可能性)
相同的方式运行,但需要进行一次额外检查,以确保我们只按字母顺序获得可能性,从而消除排列。然后,如上所述再次发生

(作为补充,如果你想在一个袋子里储存,比如说两杯水,只需将
a@
更改为
a@=

项(水,1)。
项目(花卉,1)。
项目(文件,1)。
项目(肉,2)。
项目(木材,2)。
项目(玻璃,2)。
项目(石头,3)。
项目(黄金,3)。
项目(金属,3)。
项目(铂,4)。
%行李最大容量
最大容量(10)。
地点(可能性、容量):-
最大容量(maxcapacity),
介于(1,最大容量,容量),
可能性(容量,[],可能性)。
可能性(当前、当前、当前):-
当前\=[]。
可能性(容量,[],可能性):-
项目(A、B),
B=<容量,
新容量是容量-B,
可能性(新产能[A],可能性)。
可能性(容量、[当前|剩余]、可能性):-
项目(A、B),
B=<容量,
新容量是容量-B,
当前,,
可能性(新容量、[A、当前|剩余]、可能性)。

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

可能性(u,Current,Current)
将当前工作可能性与查询统一,以返回当前可能性作为结果<代码>当前\=[]
用于消除空包的可能性(基于您的预期结果)

回溯后,
可能性(容量,[],可能性)
用于查找行李中的初始元素。将选择适合装入袋子的第一个项目,然后我们重复(首先是上面的统一条款,然后是下面的部分装满袋子条款)。一旦袋子里的这件物品用尽了所有的可能,我们回过头来寻找下一件合适的物品

可能性(容量,[Current | Rest],可能性)
基本上以与
可能性(容量,[],
?- space(Possibility, [], 0, 2), increasing(Possibility).
Possibility = [flower, water] ;
Possibility = [paper, water] ;
Possibility = [flower, paper] ;
Possibility = [meat] ;
Possibility = [wood] ;
Possibility = [glass] ;
false.
increasing([]).
increasing([_]).
increasing([X,Y|Xs]) :-
    X @< Y,
    increasing([Y|Xs]).
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).