【问题标题】:Find best result without findall and a filter在没有 findall 和过滤器的情况下找到最佳结果
【发布时间】:2013-12-10 17:25:47
【问题描述】:

我在 Prolog 中有点吃不消。

我有一个对象集合。这些物体有一定的尺寸,因此有重量。

我想将这些对象分成 2 组(它们一起构成整个组),以使它们的总重量差异最小。

我尝试的第一件事是以下(伪代码):

-> findall with predicate createSets(List, set(A, B))
-> iterate over results while
---> calculate weight of both
---> calculate difference
---> loop with current difference and compare to current difference
       till end of list of sets

这很简单。这里的问题是我有一个 +/- 30 个对象的列表。创建所有可能的集合会导致堆栈溢出。

辅助谓词:

sublist([],[]).
sublist(X, [_ | RestY]) :-
  sublist(X,RestY).
sublist([Item|RestX], [Item|RestY]) :-
  sublist(RestX,RestY).

subtract([], _, []) :-
  !.
subtract([Head|Tail],ToSubstractList,Result) :-
  memberchk(Head,ToSubstractList),
  !,
  subtract(Tail, ToSubstractList, Result).
subtract([Head|Tail], ToSubstractList, [Head|ResultTail]) :-
  !,
  subtract(Tail,ToSubstractList,ResultTail).

generateAllPossibleSubsets(ListToSplit,sets(Sublist,SecondPart)) :-
  sublist(Sublist,ListToSplit),
  subtract(ListToSplit, Sublist, SecondPart).

这些可以按如下方式使用:

:- findall(Set, generateAllPossibleSubsets(ObjectList,Set), ListOfSets ),
   findMinimalDifference(ListOfSets,Set).

所以因为我认为这是一种错误的做法,所以我想我会以迭代的方式尝试它。这是我目前所拥有的:

totalWeightOfSet([],0).
totalWeightOfSet([Head|RestOfSet],Weight) :-
  objectWeight(Head,HeadWeight),
  totalWeightOfSet(RestOfSet, RestWeight),
  Weight is HeadWeight + RestWeight.

findBestBalancedSet(ListOfObjects,Sets) :-
  generateAllPossibleSubsets(ListOfObjects,sets(A,B)),
  totalWeightOfSet(A,WeightA),
  totalWeightOfSet(B,WeightB),
  Temp is WeightA - WeightB,
  abs(Temp, Difference),
  betterSets(ListOfObjects, Difference, Sets).

betterSets(ListOfObjects,OriginalDifference,sets(A,B)) :-
  generateAllPossibleSubsets(ListOfObjects,sets(A,B)),
  totalWeightOfSet(A,WeightA),
  totalWeightOfSet(B,WeightB),
  Temp is WeightA - WeightB,
  abs(Temp, Difference),
  OriginalDifference > Difference,
  !,
  betterSets(ListOfObjects, Difference, sets(A, B)).
betterSets(_,Difference,sets(A,B)) :-
  write_ln(Difference).

这里的问题是它返回了一个更好的结果,但它没有遍历整个解决方案树。我觉得这是我在这里缺少的默认 Prolog 方案。

所以基本上我希望它告诉我“这两组差异很小”。

编辑:

What are the pros and cons of using manual list iteration vs recursion through fail

这是一个可能的解决方案(通过失败递归),但它不能失败,因为它不会返回最佳集合。

【问题讨论】:

  • 我不会先生成所有可能的集合,计算差异,然后取最小值。这是为了得到答案而囤积太多数据。你能寻找成对的集合,在你找到它时计算这对的差异,并在你去的时候保留最后一个差异最小的对吗?
  • 这确实是我想要做的。我似乎无法让它给出一个独特的结果。代码见编辑。

标签: algorithm prolog


【解决方案1】:

我会生成 30 个对象列表,按重量降序排序,然后将对象从排序列表中逐一弹出,并将每个对象放入两组中的一组中,这样我就可以得到两者之间的最小差异设置在每一步。每次我们向集合中添加一个元素时,只需将它们的权重相加,以跟踪集合的权重。从两个空集合开始,每个集合的总权重为 0。

它可能不是最好的分区,但可能会接近它。

一个非常简单的实现:

pair(A,B,A-B).

near_balanced_partition(L,S1,S2):-
  maplist(weight,L,W),      %// user-supplied predicate weight(+E,?W).
  maplist(pair,W,L,WL),
  keysort(WL,SL),
  reverse(SL,SLR),
  partition(SLR,0,[],0,[],S1,S2).

partition([],_,A,_,B,A,B).
partition([N-E|R],N1,L1,N2,L2,S1,S2):-
   (    abs(N2-N1-N) < abs(N1-N2-N)
   ->   N3 is N1+N,
        partition(R,N3,[E|L1],N2,L2,S1,S2)
   ;    N3 is N2+N,
        partition(R,N1,L1,N3,[E|L2],S1,S2)
   ).

如果您坚持要找到准确的答案,则必须将列表的所有分区生成为两组。然后在生成时,您将保持当前的最佳状态。

剩下的最重要的事情是找到迭代生成它们的方法。

一个给定的对象要么包含在第一个子集中,要么包含在第二个子集中(你没有提到它们是否都不同;让我们假设它们是不同的)。因此,我们有一个代表分区的 30 位数字。这允许我们独立枚举它们,所以我们的 state 是最小的。对于 30 个对象,将生成 2^30 ~= 10^9 个分区。

exact_partition(L,S1,S2):-
  maplist(weight,L,W),      %// user-supplied predicate weight(+E,?W). 
  maplist(pair,W,L,WL),
  keysort(WL,SL),           %// not necessary here except for the aesthetics 
  length(L,Len), length(Num,Len), maplist(=(0),Num),
  .....

您将必须实现二进制算术以在每个步骤中将 1 加到 Num,并根据新的 NumSL 生成两个子集,可能在一个融合操作中。对于每个新生成的子集,很容易计算其权重(这个计算也可以融合到相同的生成操作中):

  maplist(pair,Ws,_,Subset1),
  sumlist(Ws,Weight1),
  .....

这个二进制数 Num 与不变的列表 SL 一起代表了我们在搜索空间中的当前位置。因此搜索将是迭代的,即在恒定空间中运行。

【讨论】:

  • 这个解决方案实际上超出了我的需要。它非常优雅和流畅!非常感谢你。我现在要试一试! :)
  • @ChristopheDeTroyer 不客气,很高兴为您提供帮助。 :) 如果你成功运行了这两个程序,你能告诉我们结果吗:time( ... ) 和 Infs 它需要;第一个程序的近似结果与第二个程序找到的真正最佳值相差多远? :)
猜你喜欢
  • 2012-03-29
  • 2012-02-03
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 2022-01-20
相关资源
最近更新 更多