【发布时间】: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
这是一个可能的解决方案(通过失败递归),但它不能失败,因为它不会返回最佳集合。
【问题讨论】:
-
我不会先生成所有可能的集合,计算差异,然后取最小值。这是为了得到答案而囤积太多数据。你能寻找成对的集合,在你找到它时计算这对的差异,并在你去的时候保留最后一个差异最小的对吗?
-
这确实是我想要做的。我似乎无法让它给出一个独特的结果。代码见编辑。