【发布时间】:2021-01-03 18:47:10
【问题描述】:
我正在尝试编写一个(幼稚或半幼稚的)程序,它给定一组元素和许多玩家将其除以这个玩家数量,并且对于每个这样的除法取最小值(按总和) 子集。然后,我想计算所有这些最小除法的最大值。
这被称为https://en.wikipedia.org/wiki/Maximin_share。
例如,如果我们查看集合 {1,4,6},我们可以将其划分为 2 个玩家,这样一个玩家收到 {1,4},另一个收到 {6},这里的最小值是 5。对于所有其他部门,很容易看出最小值将小于 5。
我想写一个序言谓词maximin(+Elements,+Players,-Value),它给定一个Elements(正整数)列表和一些Players返回最大值Value。
我尝试了一个非常幼稚的方法:
- 编写了一个计算某个除法的谓词。
- 使用
find all查找所有部门。 - 对于每个除法返回最小子集的值。
- 计算其中的最大值。
但是,此程序仅适用于少量输入。例如,如果我将一个包含 10 个元素的列表 Elements 并尝试将其划分为 3 玩家,即使我尝试使用 @987654329 尽可能地增加程序内存,我也会收到堆栈外错误@。
我的代码:
% returns the smaller item
mini(A,B,B):- A > B.
mini(A,B,A):- A =< B.
% Returns the Sum of the minimal subset in a division (+,-)
min_subset_value([P1],Sum1):-subset_value(P1,Sum1).
min_subset_value([P1|RestP],Min) :- RestP \= [], min_subset_value(RestP, OtherMin), subset_value(P1,A1)
, mini(A1, OtherMin, Min).
% divide_to_players(+,+,-) : Generate a division of all the Elements to N subsets
divide_to_players([],N,EmptySets):- N>=1, generate_empty_sets(EmptySets,N).
divide_to_players(Elements, 1, [Elements]):-Elements \= [].
divide_to_players(Elements, N, [P1|RestP]):- N>1, Elements \= [], subseti(P1,Elements)
, remove_subset(Elements,P1,OtherElements)
, N1 is N-1
, divide_to_players(OtherElements, N1, RestP).
% Generates all divisions (+,+,-)
generate_all_divisions(Elements,N,AllDivs) :- findall(Div,divide_to_players(Elements,N,Div),AllDivs).
% From all the given divisions, which one has the maximal minimal subset
find_max_division([],0).
find_max_division([Set1|RestSets],Max) :- find_max_division(RestSets, OtherMin)
, min_subset_value(Set1,LocalMin)
, maxi(LocalMin, OtherMin, Max).
% uses the previous functions as described above (+,+,-)
maximin_player(Elements,N,Maximin) :- generate_all_divisions(Elements,N,AllDiv)
, find_max_division(AllDiv,Maximin).
但是,如果还有其他方法可以继续下去,我正在徘徊吗?也许在不使用findall 的情况下找到最大值?我只使用了findall,因为我没有更好的方法,所以我很高兴听到其他想法或方法来解决这个问题。
【问题讨论】:
-
所有元素都必须是整数,对吧?
-
正确@gusbro。