2

我想写一个算法来生成所有可能的唯一排列n个组,共个人们可以坐在圆形餐桌旁座位。用餐者的安排只考虑了群体成员,而不确定群体中的个人。任何两种安排在反思或轮换中都被认为是相同的。

例如,这是一种n=4和m=3的安排(编辑,因为有4组3人). 我把它画成了正方形,但几何图形无关紧要。

0 1 2 01     32     13 2 3 0

以下安排被视为与上述相同:

1 2 0 3        0 2 1 0        2 3 2 30     1        3     1        1     0 1     0        1     2        0     1 2 3 2 3        0 3 2 3        1 2 0 3

我首先采用的策略是迭代深度优先搜索。我将候选项存储在堆栈中,其中每个候选项都是一个整数数组。每次迭代时,我都会向每个候选数组中添加符合规则的整数。如果达到了所需的数组长度,则我将完成的排列从堆栈中弹出并存储在列表中。否则,我会将其添加回堆栈以供进一步考虑。

上述操作会产生大量重复项。例如,这些都是等效的:

  • 0,1,2,0,3,1,0,3,2,3,2,1
  • 0,1,2,3,2,3,0,1,3,0,2,1
  • 0,1,3,0,2,1,0,1,2,3,2,3
  • 0,2,1,0,1,2,3,2,3,0,1,3
  • 0,3,1,0,3,2,3,2,1,0,1,2
  • 0,3,2,3,2,1,0,1,2,0,3,1
  • 1,0,1,2,0,3,1,0,3,2,3,2
  • 1,0,1,2,3,2,3,0,1,3,0,2
  • 1,0,3,2,3,2,1,0,1,2,0,3
  • 1,2,0,3,1,0,3,2,3,2,1,0
  • 1,2,3,2,3,0,1,3,0,2,1,0
  • 1,3,0,2,1,0,1,2,3,2,3,0
  • 2,0,3,1,0,3,2,3,2,1,0,1
  • 2,1,0,1,2,0,3,1,0,3,2,3
  • 2,1,0,1,2,3,2,3,0,1,3,0
  • 2,3,0,1,3,0,2,1,0,1,2,3
  • 2,3,2,1,0,1,2,0,3,1,0,3
  • 2,3,2,3,0,1,3,0,2,1,0,1
  • 3,0,1,3,0,2,1,0,1,2,3,2
  • 3,0,2,1,0,1,2,3,2,3,0,1
  • 3,1,0,3,2,3,2,1,0,1,2,0
  • 3,2,1,0,1,2,0,3,1,0,3,2
  • 3,2,3,0,1,3,0,2,1,0,1,2
  • 3,2,3,2,1,0,1,2,0,3,1,0

然后,我从上述过程生成的数组列表中删除重复项。为此,我比较数组以考虑旋转(通过使用增加的偏移量进行成对比较)和反射。这很耗时。

编辑:遗漏了重要约束:相邻的两个人不能来自同一组。

我的问题是:如何通过在生成过程中避免重复来加快上述速度?一个部分的答案是从固定数组中的第一个元素开始,即坚持它以零开始,因为任何排列都可以旋转以使组在特定位置以零表示。这是一个改进,因为在上述情况下,它只会产生6个安排,而不是全部24个安排。但是,我能做得更好吗?

14
  • 1
    这里有两种不同的方法:(1)找到一种更快的方法来消除重复;(2) 找到生成较少重复项的生成方法。
    – 斯特夫
    评论 1月24日10:48
  • 1
    对于(1),应该有一种方法可以相对高效地将每个数组映射到“规范代表”,以便所有重复的数组都具有相同的规范代表。例如,这可以是词典编纂顺序中最小的数组。
    – 斯特夫
    评论 1月24日10:49
  • 1
    我对第一个例子感到困惑。您定义了具有⻕不可区分成员的⻕组,所以我希望在表示中看到⻕不同的值,其中每个不同的值代表一个组,因此出现⻕次。但您的示例显示𝑛=3,𝑚=4,但有4个不同的值,每个值重复3次。你能澄清一下吗?
    – 三角帆
    评论 1月24日12:21
  • 1
    “编辑:错过了重要限制:相邻的两个人不能来自同一组。”<<这让我大笑起来
    – 斯特夫
    评论 1月24日16:31
  • 1
    对不起@Stef。当我最初想到这个问题时,非邻接约束是我最关心的问题。当我发现生成了多少重复/非规范排列时,我的注意力转移了,我在这里的描述中忽略了它(这是一个遗憾,因为它可以说是最重要的事情)。 评论 1月24日18:15

1答案1

重置为默认值
0

您可以将每个排列映射到该排列所有重复项的规范代表,而不是比较所有排列对以检查其中是否存在重复项,并拒绝所有不规范的排列。

如果安排有长度米*n,但你有N个重复排列,其中米*n相对较小,但N个是巨大的,那么比较所有成对的排列将采取以下顺序牛*牛*米*牛操作,而筛选出非规范安排只需要牛*米*牛操作。

此外,由于表是循环的,您可以修复任意元素,并将其视为始终是第一个元素。这样,只需向置换生成算法传递一个元素,就可以立即避免生成大量重复项。

在这里,我生成所有座位更多交互工具.distinct_permutations,并过滤掉它们的旋转和反射的等价类中在字典上不是最小的座位。

定义最小值(seq):qes=序列[::-1]返回(范围(len(seq))中i的所有(seq<=qes[i:]+qes[:i])和所有(seq<=seq[i:]+seq[:i]表示范围内的i(len(seq)))从more_intertools导入distinct_permutations从字符串导入打印为字母def座位(n,m):“”“n组m人的所有可能座位,直至反射/旋转”“”池=“0”*(m-1)+字母[1:n]*mresult=(''.join(('0',*seating)),用于distinct_permutations(pool)中的座位)结果=[如果最小(座位),则结果中的座位数]返回结果l42=座位(4,2)打印(len(l42))# 171打印(l42)# ['00112233', '00112323', '00112332', '00113223', '00113232', '00113322', '00121233', '00121323', '00121332', '00122133', '00122313', '00122331', '00123123', '00123132', '00123213', '00123231', '00123312', '00123321', '00131223', '00131232', '00131322', '00132123', '00132132', '00132213', '00132231', '00132312', '00133122', '00133212', '00211233', '00211323', '00211332', '00212133', '00212313', '00213123', '00213132', '00213213', '00213312', '00221133', '00221313', '00223113', '00231123', '00231132', '00231213', '00232113', '00311223', '00312123', '00312213', '00321123', '01012233', '01012323', '01012332', '01013223', '01013232', '01013322', '01021233', '01021323', '01021332', '01022133', '01022313', '01023123', '01023132', '01023213', '01031223', '01032123', '01102233', '01102323', '01102332', '01103223', '01120233', '01120323', '01120332', '01122033', '01122303', '01123023', '01123032', '01123203', '01123302', '01130223', '01130232', '01130322', '01132023', '01132032', '01132203', '01132302', '01133022', '01133202', '01201233', '01201323', '01201332', '01202133', '01202313', '01202331', '01203123', '01203132', '01203213', '01203231', '01203312', '01203321', '01210233', '01210323', '01212033', '01212303', '01213023', '01213032', '01213203', '01213302', '01220133', '01220313', '01220331', '01221033', '01221303', '01223013', '01223031', '01223103', '01230123', '01230132', '01230213', '01230231', '01230312', '01230321', '01231023', '01231032', '01231203', '01231302', '01232013', '01232031', '01232103', '01233102', '01301322', '01302123', '01302132', '01302213', '01302231', '01302312', '01303122', '01303212', '01310223', '01310232', '01312023', '01312032', '01312203', '01312302', '01313022', '01313202', '01320132', '01320213', '01320231', '01320312', '01321203', '01321302', '01323102', '01330212', '01331022', '01331202', '02021133', '02021313', '02023113', '02031123', '02031213', '02112033', '02112303', '02113023', '02113032', '02113203', '02120313', '02121303', '02130213', '02130312', '02131203', '02203113', '02211303']l43=座位(4,3)打印(len(l43))# 15402打印(l43)# ['000111222333', '000111223233', '000111223323', '000111223332', '000111232233', '000111232323', '000111232332', '000111233223', '000111233232', '000111233322', ..., '022121130303', '022203031113', '022211130303']

为了记录在案,差异替代('00111222333')生成92400个排列,其中我们保留15402个。

  • 1
    通过将任意元素固定为规范表示中的第一个元素,并将其添加到座椅。所以不同的置换产生长度排列n-1个(省略该元素的一次出现),然后在固定元素之前添加。 评论 1月24日14:56
  • @迪伦·戴维斯确实如此。我甚至不能从传递到的池中删除该元素的所有n个副本不同的置换,以便排列具有长度n*(m-1)而不是米*n,然后以智能方式重新插入n个副本?
    – 斯特夫
    评论 1月24日15:03
  • 1
    我认为这不会消除许多重复。唯一的额外重复数据消除不同的置换尚未处理的是排列的翻转/反转。我不知道如何消除这种情况。 评论 1月24日15:59

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.