对于不同排列的数量,许多组合问题具有n!/(m!* p!* q!...)的形式。是否有任何有效的算法来枚举所有不同的排列?
让我们用一个例子来解决问题。假设有10个人想玩5v5游戏。为了帮助他们建立一场比赛(即谁进入每支球队),我们想列举所有可能的对决。有多少场比赛?总的来说,有10个! = 3628800安排球员的可能方式。然而,交换球队1内的球员并没有改变任何东西(A + B + C + D + E对F + G + H + I + J与B + A + C + D + E对F + G + H相同+ I + J),所以我们必须将这个数字除以5!交换球队内的球员相同2.将球队1和球队2交换到同一场比赛,所以我们想把最终结果除以2.最后,有10!/(5!* 5!* 2!) = 126个不同的对决。有没有办法找到它们?
天真算法将枚举所有玩家排列,并且仅返回对战的“规范”表示(例如,在团队内部玩家必须按字典顺序排序)。然而,这非常低效;对于8对8的游戏,我们必须枚举并评估16! (超过20万亿)排列,以列举6435个不同的对决。是否有任何非天真的选择?
答案 0 :(得分:0)
“A”必须在其中一个团队中,所以我们可以创建所有内部都有“A”的团队,以避免获得相同的组合。
对于每个组,我们都会查看可以添加的所有可能的新元素。如果你添加一个元素,那么只允许添加稍后在该列表中的元素(在still_available = available [i:]中完成),以便不为每个团队获得每个排列。
如果一个组有足够的成员(5)将其添加到列表中,并且有可能。
由于你需要至少5个成员,你需要添加索引0,...,len(可用) - (5 - len(fixed_group) - 1)中的一个成员,因为否则只会有len(fixed_group) )你已经选择并且(5 - len(fixed_group) - 1)可用左边小于5.
input = ["B", "C", "D", "E", "F", "G", "H", "I", "J"]
global_poss_groups = []
def recursive_find_groups(fixed_group, available):
if len(fixed_group) == 5:
global_poss_groups.append(fixed_group)
return -1
for i in range(len(available) - ( 5 - len(fixed_group) - 1)):
still_available = available[i:]
new_element = still_available.pop(0)
new_group = fixed_group[:]
new_group.append(new_element)
recursive_find_groups(new_group, still_available)
recursive_find_groups(["A"], input)
print(global_poss_groups)
print(len(global_poss_groups))
答案 1 :(得分:0)
枚举而不重复的关键通常是选择规范排序。例如,要枚举从大小为k
的Universe中选择的n
元素的组合,我们可以通过仅按排序顺序生成组合来确保唯一性。 (即使宇宙中包含重复的元素,也可以使其工作,但这与此无关。)
在将球员分配给球队的情况下,我们正在寻找一个大小为kn
的球体划分为k
个球队的n
球员。 (在您的示例中,k
是两个,但很容易推广到k
的任何值。)我们通过以下方式进行规范选择:
对每个队伍中的球员进行排序
按第一位玩家排序球队
我们在参数k
上递归枚举分区。
如果k
为1,则解决方案只是一组玩家(按排序顺序)作为一个团队。对于k
的任何较大值,我们将第一个玩家放入第一个团队,然后:
对于使用所选玩家创建的每个第一个团队以及剩余玩家中n-1
个玩家的一些(已排序)组合:
(k-1)*n
名玩家的所有分区枚举为k-1
个小组。解决了不同(但相似)的分区枚举问题in this SO post。该答案包含一般迭代机制,可用于许多类似的问题,包括这个问题。