【问题标题】:Shuffle vector elements such that two similar elements coming together at most twice洗牌向量元素,使两个相似的元素最多出现两次
【发布时间】:2021-10-27 18:43:03
【问题描述】:

举个例子:

我有一个名为 vec 的向量,其中包含十个 1 和十个 2。我正在尝试随机排列它,但有一个条件是两个相同的值不能超过两次。

到目前为止,我所做的是使用 randperm 函数生成 vec 的随机索引并相应地改组 vec。这就是我所拥有的:

vec = [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2];
atmost = 2;
indexes = randperm(length(vec));
vec = vec(indexes);

>> vec =
      2  1  1  1  2  1  2  1  2  1  1  1  2  2  1  2  1  2  2  2

我的代码随机排列 vec 的元素,但不满足两个相似值最多出现两次的条件。我怎样才能做到这一点?有什么想法吗?

【问题讨论】:

  • 我强烈建议添加标签,让有知识回答的人注意到您的问题。至少algorithm 可能还有combinatorics。我会为您添加它们,但我不知道您要替换哪些现有标签。

标签: matlab vector random constraints shuffle


【解决方案1】:

您可以先确定一个值的游程长度,然后在它们周围拟合其他值。

在解释中,我将在向量中使用 ab 的值,以免混淆向量元素的值(1 和 2)以及每个元素的游程长度(1 和 2)。

最终目标是使用repelem 来构造洗牌向量。 repelem 采用要重复的元素的向量,以及每个元素重复多少次的向量。例如,如果我们有:

v = [b   a   b   a   b   a   b   a   b   a   b   a   b   a   b   a   b]
n = [1   1   1   2   1   1   2   1   2   1   1   1   1   2   1   1   0]

repelem 将返回:

shuffled_vec = [b  a  b  a  a  b  a  b  b  a  b  b  a  b  a  b  a  a  b  a]

作为第一步,我将为与a 值对应的计数生成随机值。在这个例子中,这将是:

a_grouping = [1   2   1   1   1   1   2   1]

首先,随机选择分组向量中 2 的个数。最多可以有n/2 个。然后加 1 组成所需的总数。

num_total = 10;   % number of a's (and b's)
% There can be 0..num_total/2 groups of two a's in the string.
two_count = randi(num_total/2 + 1) - 1;
% The remainder of the groups of a's have length one.
one_count = num_total - (2*two_count);
% Generate random permutation of two_count 2's and one_count 1's
a_grouping = [repmat(2, 1, two_count), repmat(1, 1, one_count)];

这会给我们类似的东西:

a_grouping = [2   2   1   1   1   1   1   1]

现在随机播放:

a_grouping = a_grouping(randperm(numel(a_grouping)));

结果:

a_grouping = [1   2   1   1   1   1   2   1]

现在我们需要弄清楚b 值的去向。每次运行a 值之间必须至少有一个b(最多两个),并且字符串的开头和结尾可能有0、1 或2 个b 值。所以我们需要为下面的每个xy 值生成计数:

all_grouping = [y  1  x  2  x  1  x  1  x  1  x  1  x  2  x  1  y]

x必须至少为 1,因此我们将首先分配它们。由于 y 的值可以是 0、1 或 2,因此我们将它们设置为 0。

% Between each grouping of a's, there must be at least one b.
% There can be 0, 1, or 2 b's before and after the a's,
% so make room for them as well.
b_grouping = zeros(1, numel(a_grouping) - 1 + 2);
b_grouping(2:end-1) = 1;   % insert one b between each a group

对于我们需要分配的每个剩余计数,只需选择一个随机槽。如果它还没有被填满(即如果它

% Assign location of remaining 2's 
for s = numel(a_grouping):num_total
   unassigned = true;
   while unassigned
      % generate random indices until we find one that's open 
      idx = randi(numel(b_grouping));
      if b_grouping(idx) < 2
         b_grouping(idx) = b_grouping(idx) + 1;
         unassigned = false;
      end
   end
end

现在我们对ab 分别进行计数:

a_grouping = [1   2   1   1   1   1   2   1]
b_grouping = [1   1   1   2   2   1   1   1   0]

我们将构建值向量(示例开头的v)并交错分组(n 向量)。

% Interleave the  a and b values
group_values = zeros(1, numel(a_grouping) + numel(b_grouping));
group_values(1:2:end) = 2;
group_values(2:2:end) = 1;
% Interleave the corresponding groupings
all_grouping = zeros(size(group_values));
all_grouping(2:2:end) = a_grouping;
all_grouping(1:2:end) = b_grouping;

最后,repelem 将所有内容放在一起:

shuffled_vec = repelem(group_values, all_grouping)

最终结果是:

shuffled_vec =
   1   2   2   1   1   2   1   1   2   2   1   1   2   2   1   1   2   2   1   2

完整代码:

num_total = 10;   % number of a's (and b's)
% There can be 0..num_total/2 groups of two a's in the string.
two_count = randi(num_total/2 + 1) - 1;
% The remainder of the groups of a's have length one.
one_count = num_total - (2*two_count);
% Generate random permutation of two_count 2's and one_count 1's
a_grouping = [repmat(2, 1, two_count), repmat(1, 1, one_count)];
a_grouping = a_grouping(randperm(numel(a_grouping)));
% disp(a_grouping)

% Between each grouping of a's, there must be at least one b.
% There can be 0, 1, or 2 b's before and after the a's,
% so make room for them as well.
b_grouping = zeros(1, numel(a_grouping) - 1 + 2);
b_grouping(2:end-1) = 1;   % insert one b between each a group
% Assign location of remaining 2's 
for s = numel(a_grouping):num_total
   unassigned = true;
   while unassigned
      % generate random indices until we find one that's open 
      idx = randi(numel(b_grouping));
      if b_grouping(idx) < 2
         b_grouping(idx) = b_grouping(idx) + 1;
         unassigned = false;
      end
   end
end

% Interleave the  a and b values
group_values = zeros(1, numel(a_grouping) + numel(b_grouping));
group_values(1:2:end) = 2;
group_values(2:2:end) = 1;
% Interleave the corresponding groupings
all_grouping = zeros(size(group_values));
all_grouping(2:2:end) = a_grouping;
all_grouping(1:2:end) = b_grouping;

shuffled_vec = repelem(group_values, all_grouping)

【讨论】:

    【解决方案2】:

    这应该会生成相当随机的非连续向量。是否统一涵盖所有可能性,我不确定。

    out=[];
    for i=1:10
        if randi(2)==1
            out=[out,1,2];
        else
            out=[out,2,1];
        end
    end
    disp(out)
    

    示例结果

    1,2,1,2,1,2,1,2,2,1,2,1,1,2,2,1,2,1,1,2,
    2,1,2,1,1,2,2,1,2,1,1,2,2,1,2,1,1,2,1,2,
    1,2,2,1,2,1,1,2,1,2,2,1,2,1,2,1,2,1,2,1,
    2,1,2,1,2,1,1,2,1,2,2,1,1,2,2,1,2,1,1,2,
    2,1,1,2,1,2,1,2,2,1,2,1,1,2,1,2,1,2,1,2,
    2,1,1,2,2,1,2,1,1,2,1,2,2,1,1,2,1,2,2,1,
    1,2,2,1,1,2,1,2,2,1,2,1,2,1,1,2,2,1,1,2,
    2,1,1,2,2,1,2,1,1,2,2,1,1,2,1,2,1,2,1,2,
    1,2,2,1,1,2,1,2,2,1,2,1,1,2,1,2,1,2,1,2,
    1,2,1,2,2,1,2,1,2,1,2,1,1,2,1,2,2,1,2,1,
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-05
      • 1970-01-01
      • 2022-11-26
      • 1970-01-01
      • 2018-05-03
      相关资源
      最近更新 更多