通过将每个元素交换不超过k个位置来置换n个元素

时间:2014-02-10 00:49:24

标签: matlab permutation constraint-programming

我所拥有的是一个向量(示例中n = 4):

x = '0123';

我想要的是一个x大小相同的矢量y,并且x中的元素与x中的元素顺序不同:

y = ['0123'; '0132'; '0213'; '0231'; '0312'; '0321'; '1023'; '1032'; '1203'; '1302'; '2013'; '2031'; '2103'; '2301'];
y(ceil(rand * numel(y(:, 1))), :)

即。排列使得y中的每个元素被允许相对于其在x中的原始位置随机改变不超过k个位置(在该示例中k = 2)。概率分布必须是均匀的(即每个排列必须同样可能发生)。

一种明显但效率低下的方法当然是找到一个随机的无约束排列,并事后检查这是否恰好符合约束条件。对于小向量,您可以找到所有排列,删除不允许的排列,并随机选择其余排列。 有关如何更有效地做同样事情的想法,例如通过实际交换元素吗?

2 个答案:

答案 0 :(得分:3)

使用约束编程可以轻松地生成所有排列。以下是使用MiniZinc的上述示例的简短模型(请注意,我们假设x在此处将包含n个不同的值):

include "globals.mzn";

int: k = 2;
int: n = 4;
array[1..n] of int: x = [0, 1, 2, 3];
array[1..n] of var int: y;

constraint forall(i in 1..n) (
    y[i] in {x[i + offset] | offset in -min(k, i-1)..min(k, n-i)}
  );

constraint all_different(y);

solve :: int_search(y, input_order, indomain_min, complete)
  satisfy;

output [show(y)];

在大多数情况下,约束编程系统可以使用随机搜索。但是,这不会给您统一的结果分布。然而,使用CP将比天真的方法(生成和测试有效性)更有效地生成所有有效的排列。

如果您需要有效地生成类型的随机排列,我认为可以修改标准Fisher-Yates shuffle来直接处理它。标准算法使用数组的其余部分从中选择下一个值,并选择具有均匀概率分布的值。应该可以保留仅当前有效选择的列表,并更改值的概率分布以匹配所需的输出。

答案 1 :(得分:1)

除了你提到的拒绝方法之外,我没有看到任何方法。但是,不是列出所有允许的排列然后选择一个,而是避免列表更有效。因此,您可以随机生成排列,检查它是否有效,如果不是则重复:

x = '0123';
k = 2;

n = numel(x);
done = 0;
while ~done
    perm = randperm(n);
    done = all( abs(perm-(1:n)) <= k ); %// check condition
end
y = x(perm);
相关问题