我正在寻找一种用C,C ++,Python或Java实现的算法,该算法计算 n 代理的获胜联盟集,其中每个代理具有不同的投票数。我会很感激任何提示。谢谢!
答案 0 :(得分:3)
换句话说,你有一个数组X[1..n]
,并希望拥有sum(subset) >= 1/2 * sum(X)
的所有子集,对吧?
这可能意味着整套资格。
之后,您可以删除k
的所有元素X[k] < 1/2 * sum(X)
,并且每个这样的联盟也可以作为答案。
之后,您可以逐个删除元素,当达到总和的一半时停止。
这显然是 不是最有效的解决方案:如果您已尝试k1=1,k2=2
,则不想放弃k1=2,k2=1
- 但我相信您可以处理此问题
答案 1 :(得分:1)
很高兴能够通过递归分成两种情况来解决这个问题:找到所有获胜的“联盟”,包括最后一个“代理人”和所有没有最后一个“代理人”的人。现在,对于这些子问题中的每一个,可以应用相同的逻辑,在包括最后“代理”的情况下具有较低的目标投票数。当目标投票数低于或等于零时,或者当没有更多的代理商离开时,停止递归。
请注意,在这样的算法中,根据投票数对代理商进行排序是有益的。
示例实施:
from itertools import combinations
def _winning_coalitions(agents, target_votes):
"""recursive solving function
@param agents: sequence of (name, votes) pairs
@param target_votes: minimum number of votes for a coalition
"""
if target_votes <= 0:
# stop the recursion
for coalition_size in range(len(agents)+1):
for coalition in combinations(agents, coalition_size):
yield coalition
elif not agents:
pass # no agents, so no possible coalitions
else:
agent_name, agent_votes = agents[-1]
agents = agents[:-1]
for coalition in _winning_coalitions(agents, target_votes-agent_votes):
yield ((agent_name, agent_votes),) + coalition
if sum([votes for (name, votes) in coalition]) >= target_votes:
yield coalition
def winning_coalitions(agents):
"""find all coalitions with at least target_votes combined votes
@param agents: dictionary of the form: name -> number of votes
"""
target_votes = (sum(agents.values())-1)//2+1
agents = sorted(agents.items(), key=operator.itemgetter(1))
coalitions = _winning_coalitions(agents, target_votes)
return sorted([sorted([name for (name, votes) in c]) for c in coalitions])
在Python解释器中:
>>> agents = {"Alice": 3, "Bob": 5, "Charlie": 7, "Dave": 4}
>>> # divide sum of votes by 2, rounding up
>>> target_votes = (sum(agents.values())-1)//2+1
>>> # solve!
>>> coalitions = winning_coalitions(agents, target_votes)
>>> sorted([sorted(c) for c in coalitions])
[['Alice', 'Bob', 'Charlie'],
['Alice', 'Bob', 'Charlie', 'Dave'],
['Alice', 'Bob', 'Dave'],
['Alice', 'Charlie'],
['Alice', 'Charlie', 'Dave'],
['Bob', 'Charlie'],
['Bob', 'Charlie', 'Dave'],
['Charlie', 'Dave']]
答案 2 :(得分:0)
将每个代理的投票数排列到一个数组中,并从右边计算部分和,这样你只需要查找部分和就可以找到SUM_i = k到n个Votes [i]。 / p>
然后对{1,2,... n}的所有可能子集进行回溯搜索。在回溯中的任何一点,您已经接受了一些代理0..i - 1的子集,并且您从部分总和中了解了其他代理可用的最大可能投票数。因此,您可以查看是否可以使用代理编号&gt; = i扩展当前子集以形成获胜联盟,如果不是,则将其丢弃。
这为您提供了一个回溯搜索,只有当它已经是一个获胜的联盟时才考虑子集,或者您将其扩展为一个成功的联盟。因此,我认为回溯搜索的成本是您发现的获胜联盟的大小的总和,这似乎接近最优。我很想在运行之前重新安排代理人,这样你就可以先处理得票最多的代理人,但目前我没有看到一个说你从中获得很多收益的论据。
实际上 - 从Alf的回答中得到一个提示 - 如果从全套代理开始,然后使用回溯搜索来决定丢弃哪些代理,那么生活会容易得多。那么你不需要一个部分和的数组,你只需要生成你想要的子集。是的,没有必要提前订购代理商。