找到一组具有约束的排列

时间:2009-08-21 23:15:35

标签: algorithm permutation

我有一组N ^ 2个数字和N个bin。假设每个bin具有分配给它的集合中的N个数字。我面临的问题是找到一组分布,将数字映射到容器,满足约束条件,每对数字只能共享同一个bin。

分布可以很好地用NxN矩阵表示,其中每行代表一个bin。然后问题是找到一组矩阵元素的排列,其中每对数字只共享同一行一次。它与哪一行无关,只有两个数字都分配给同一行。

满足N = 8的约束的3个排列的示例组:

 0  1  2  3  4  5  6  7
 8  9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63
 0  8 16 24 32 40 48 56
 1  9 17 25 33 41 49 57
 2 10 18 26 34 42 50 58
 3 11 19 27 35 43 51 59
 4 12 20 28 36 44 52 60
 5 13 21 29 37 45 53 61
 6 14 22 30 38 46 54 62
 7 15 23 31 39 47 55 63
 0  9 18 27 36 45 54 63
 1 10 19 28 37 46 55 56
 2 11 20 29 38 47 48 57
 3 12 21 30 39 40 49 58
 4 13 22 31 32 41 50 59
 5 14 23 24 33 42 51 60
 6 15 16 25 34 43 52 61
 7  8 17 26 35 44 53 62

不属于上述集合的排列:

 0 10 20 30 32 42 52 62
 1 11 21 31 33 43 53 63
 2 12 22 24 34 44 54 56
 3 13 23 25 35 45 55 57
 4 14 16 26 36 46 48 58
 5 15 17 27 37 47 49 59
 6  8 18 28 38 40 50 60
 7  9 19 29 39 41 51 61

由于与第二个排列的多次碰撞,因为例如它们都将一行中的数字0和32配对。


枚举三是很容易的,它包括1个任意排列,它的转置和矩阵,其中行由前面的矩阵'对角线组成。

我找不到一种方法来生成一个由更多组成的集合。这似乎是一个非常复杂的问题,或者是一个不明显的解决方案的简单问题。无论哪种方式,如果有人有任何想法如何在N = 8的情况下在合理的时间内解决它,或者确定问题的正确的学术名称,我会感激,所以我可以google它。

如果你想知道什么是有用的,我正在寻找一个带有8个缓冲区的纵横交换机的调度算法,它可以为64个目的地提供流量。调度算法的这部分是输入流量不可知的,并且在多个硬连线目的地缓冲区映射之间循环切换。目标是让每对目标地址在循环周期中仅竞争相同的缓冲区一次,并最大化该周期的长度。换句话说,这样每对地址都尽可能地竞争相同的缓冲区。


编辑:

这是我的一些代码。 CODE

这很贪婪,通常在找到第三种排列后终止。但是应该存在一组满足该问题的至少N个排列。

替代方案将要求选择排列我参与寻找排列(I + 1..N),以检查排列I是否是由最大排列数组成的解的一部分。这需要枚举所有排列以检查每一步,这是非常昂贵的。

4 个答案:

答案 0 :(得分:4)

制作一个64 x 64 x 8阵列:bool禁止[i] [j] [k]表示该对(i,j)是否出现在行k中。每次在行k中使用对(i,j)时,都会将此数组中的关联值设置为1。请注意,您将只使用此数组的一半i<学家

要构造一个新的排列,首先尝试成员0,并验证至少有七个未设置的禁用[0] [j] [0]。如果没有剩下七个,请递增并再试一次。重复以填写行的其余部分。重复整个过程以填充整个NxN排列。

在实施此功能时,您应该能够提出优化措施,但这应该做得很好。

答案 1 :(得分:4)

你想要的是combinatorial block design。使用链接页面上的命名法,您需要设计大小为(n ^ 2,n,1)的最大k。这将使用您的命名法给您n(n + 1)个排列。这是计数参数在理论上可能达到的最大值(参见文章中关于从v,k和lambda推导b的解释)。对于一些素数p和整数k,使用仿射平面存在n = p ^ k的这种设计。据推测,存在的唯一仿射平面具有这种尺寸。因此,如果你可以选择n,也许这个答案就足够了。

但是,如果不是理论上可能的最大排列数,而只是想找到一个大数(对于给定的n ^ 2,你可以找到最多),我不确定调用这些对象是什么。

答案 2 :(得分:1)

可能你可以将问题重新表述为图论。例如,您从具有N×N个顶点的完整图形开始。在每个步骤中,您将图形划分为N个N-cliques,然后删除所有使用的边。

对于这个N = 8的情况,K64有64×63/2 = 2016边缘,64个批次的K8有1792个边缘,所以你的问题可能不可能: - )< / p>

答案 3 :(得分:0)

是的,贪婪的风格不起作用,因为你没有数字。

在违反约束之前,很容易看到不能超过63种排列。在64日,你必须将至少一个数字与已经配对的另一个数字配对。鸽笼原则。

事实上,如果您使用我之前建议的禁用对表,您会发现在用完之前最多只能有N + 1 = 9个排列。该表具有N ^ 2 x(N ^ 2-1)/ 2 = 2016非冗余约束,并且每个新置换将创建N x(N选择2)= 28个新配对。因此,所有配对将在2016/28 = 9个排列后用完。似乎意识到排列太少是解决问题的关键。

您可以生成N个排列的列表,编号为n = 0 ... N-1为

A_ij = (i * N + j + j * n * N) mod N^2

通过移动每个排列中的列来生成新的排列。第n个排列的顶行是第n-1排列的对角线。编辑:糟糕...这只有在N为素数时才会起作用。

这错过了最后一个排列,你可以通过转置矩阵来获得:

A_ij = j * N + i