如何解决寻找最大最小值集
我正在尝试编写一个(天真的或半天真的)程序,该程序给定了一组元素,许多玩家将其划分为该玩家数量,并且每次划分都取最小值(总和) )子集。然后,我要计算所有这些最小除法的最大值。
这就是所谓的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
个播放器,即使我尝试尽最大努力增加程序内存,也会遇到堆栈错误可以使用set_prolog_stack
。
我的代码:
% returns the smaller item
mini(A,B,B):- A > B.
mini(A,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,[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,AllDivs) :- findall(Div,divide_to_players(Elements,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,min_subset_value(Set1,LocalMin),maxi(LocalMin,Max).
% uses the prevIoUs functions as described above (+,-)
maximin_player(Elements,Maximin) :- generate_all_divisions(Elements,AllDiv),find_max_division(AllDiv,Maximin).
但是,我是否在流浪,是否还有其他方法可做?也许在不使用findall
的情况下找到maximin值?我之所以只使用findall
,是因为我对这种方法没有更好的主意,因此,我很高兴听到其他解决此问题的主意或方法。
解决方法
如果元素都是整数(即没有变量,也没有浮点值),我认为这很好:
maximin(Elements,N,Maximin,LDistribution):-
sumlist(Elements,Sum),TargetMaximin is -Sum//N,once(
(
between(TargetMaximin,-1,NMaximin),Maximin is -NMaximin,distribute(Elements,[],n,LDistributionOnce)
)),LDistribution=LDistributionOnce.
distribute([],_,[]).
distribute(Elements,Skipped,y,Cur,Distribution,[Distribution|LDistribution]):-
N>0,Cur >= Maximin,succ(N1,N),append(Elements,NElements),distribute(NElements,N1,LDistribution).
distribute([Element|Elements],LDistribution):-
N>0,NCur is Cur+Element,NCur,[Element|Distribution],[Element|Skipped],LDistribution).
算法的思想是从最大目标最小值(元素总数的整数除以玩家数量)开始,并尝试将元素放入N个插槽中,其中每个插槽的总和至少为最低目标。 如果找到这样的分布,就可以了,否则将目标最小值减小1并重复。
这里的算法还给出了找到的唯一分布。
示例运行:
?- maximin([11,17,19],3,LDist).
Maximin = 11,LDist = [[11],[17],[19]].
?- maximin([5,7,1,4,8,2,5,1],LDist).
Maximin = 16,LDist = [[3,5],[3,3],[1,8]].
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。