如何检查条款的参数是否属于列表的一部分?

时间:2017-12-20 19:46:01

标签: list prolog

所以我正在写一个背包问题,在我的任务中有一个规格,背包中不能有相同的“重量”物品。

基本上我发送我的物品清单,即“Pantry”,然后是容量,在背包和背包本身内可以有多少重量。

legalKnapsackNoSameRocks(Pantry, Capacity, Knapsack):-
   subseq2(Knapsack,Pantry),
   weight(Knapsack,W),
   W =< Capacity.

然后我制作所有可能组合的子列表

subseq2([],[]).
subseq2([Item | RestX], [Item | RestY]) :-
   not(member(arg(2, Item, X), L)),
   add_tail(L, arg(2, Item, X), L),
   subseq2(RestX,RestY).
subseq2(X, [_ | RestY]) :-
   subseq2(X,RestY).

在制作子列表时,我必须检查列表是否包含下一个项目所具有的权重,如果是,那么我不会在列表中添加相同的权重项目。

我想这样做的方法是制作一个新的清单,我在其中添加了物品的“重量”。所以基本上我检查“权重”列表是否包含我想要放入背包的物品的“重量”,如果是,我不会把它放进去。

我也做了一个“附加”谓词

add_tail([],X,[X]).
add_tail([H|T],X,[H|L]):- add_tail(T,X,L).

但它永远不会返回任何东西,它总是错误的。我认为这是因为列表首先是空的?谢谢。

编辑:

权重谓词获取背包并添加所有项目的所有权重并返回总权重。

当我运行程序时,我输入

knapsackOptimizationWithoutSameSizeRocks(
   [ rock(smallRock,2,2300), 
     rock(biggerRock,4,6700),
     rock(mediumRock,3,6900),
     rock(smallDiamond,2,9200), 
     rock(smallDiamond,2, 9200),
     rock(smallDiamond, 3, 10000)
   ], 15 ,Knapsack).

完整代码:

rock(smallDiamond,2,9200).
rock(smallRock,2,2300).
rock(biggerRock,4,6700).
rock(mediumRock,3,6900).
rock(smallDiamond,3, 10000).

knapsackOptimizationWithoutSameSizeRocks(Pantry, Capacity, Knapsack) :-
   allLegalKnapsacksNoSameRocks(Pantry, Capacity, R),
   maximumvalue(R, Knapsack),
   value(Knapsack, CALS),
   nl,print('value: '), print(CALS),
   !.

weight([],0).
weight([rock(_,W,_) | Rest], X) :-
  weight(Rest,RestW),
  X is W + RestW.

value([],0).
value([rock(_,_,C) | Rest], X) :-
  value(Rest,RestC),
  X is C + RestC.

subseq2([],[]).
subseq2([Item | RestX], [Item | RestY]) :-  
  %not(memberchk(arg(2, Item, X), [rock(_, L, _) | Rest])),

  %add_tail(L, arg(2, Item, X), L),
  %not(memberchk(Item, RestY)),
  subseq2(RestX,RestY).
subseq2(X, [_ | RestY]) :-
  subseq2(X,RestY).

%add_tail([],X,[X]).
%add_tail([H|T],X,[H|L]):- add_tail(T,X,L).

legalKnapsackNoSameRocks(Pantry, Capacity, Knapsack):-
  subseq2(Knapsack,Pantry),
  weight(Knapsack,W),
  W =< Capacity.

allLegalKnapsacksNoSameRocks(Pantry, Capacity, ListOfLegalKnapsacks) :-
   findall(LegalKnapsack,
             legalKnapsackNoSameRocks(Pantry, Capacity, LegalKnapsack),
          ListOfLegalKnapsacks).               

maximumvalue([LEGAL | LEGALS], MAXCALS) :-
   value(LEGAL, CALS),
   maxCals(LEGALS, CALS, LEGAL, MAXCALS).

maxCals([], MAXCALS, MAXCALLEGAL, MAXCALLEGAL).
maxCals([LEGAL | LEGALS], MAXCALS, MAXCALLEGAL, OUTPUT) :-
   value(LEGAL, NEWCALS), NEWCALS > MAXCALS,
   maxCals(LEGALS, NEWCALS, LEGAL,OUTPUT).
maxCals([LEGAL | LEGALS], MAXCALS, MAXCALLEGAL, OUTPUT) :-
   value(LEGAL, NEWCALS), NEWCALS =< MAXCALS,
   maxCals(LEGALS, MAXCALS, MAXCALLEGAL, OUTPUT).

我希望得到像

这样的东西
Knapsack = [rock(biggerRock, 4, 6700), rock(smallDiamond, 2, 9200), 
rock(smallDiamond, 3, 10000)].

因为这些都是不同的权重,但这个背包组合比这更有价值:

Knapsack = [rock(biggerRock, 4, 6700), rock(mediumRock, 3, 6900), 
rock(smallDiamond, 2, 9200)].

如果我可以多次使用相同的权重,那么就会给出

Knapsack = [rock(biggerRock, 4, 6700), rock(mediumRock, 3, 6900), 
rock(smallDiamond, 2, 9200), rock(smallDiamond, 2, 9200),
 rock(smallDiamond, 3, 10000)].

1 个答案:

答案 0 :(得分:1)

您可以这样写legalKnapsackNoSameRocks/3

legalKnapsackNoSameRocks(Pantry, Capacity, Knapsack) :-
  permutation(Pantry,RandomPantry),
  lknsr(RandomPantry,Capacity,[],Knapsack),
  weight(Knapsack,W),
  W =< Capacity.

lknsr([R|Rs],C,Ls0,Ls) :-
  R = rock(_,W,_),
  ( \+ member(rock(_,W,_),Ls0) ->
    Ls1 = [R|Ls0]
  ; Ls1 = Ls0 ),
  lknsr(Rs,C,Ls1,Ls).
lknsr([],_,Ls,Ls).

由于permutation/2为您提供了列表的所有可能排列,并且findall/3(在allLegalKnapsacksNoSameRocks/3中)收集了所有合法组合,maximumvalue/2可以选择最高的子集值。