【问题标题】:Matlab: How to enumerate the possible ways of forming pairs from a listMatlab:如何枚举从列表中形成对的可能方式
【发布时间】:2021-01-20 02:12:11
【问题描述】:

假设我有一个长度为2k 的列表,比如{1,2,...,2k}。将2k 数字分组为k(无序)对的可能方式有n(k) = 1*3* ... *(2k-1)。所以对于k=2,我们有以下三种不同的方式组成2对

(1 2)(3 4)

(1 3)(2 4)

(1 4)(2 3)

如何使用 Matlab 创建上述列表,即创建一个 n(k)*(2k) 矩阵,以便每一行包含将 2k 数字列表分组为 k 对的不同方式。

【问题讨论】:

  • 这个问题已经用不同的语言问过很多次了。 Python 示例:1、2、3、R 示例:1、2。也许看看这些方法会有所帮助。

标签: matlab enumeration


【解决方案1】:
clear
k = 3;
set = 1: 2*k;
p = perms(set); % get all possible permutations
% sort each two column
[~, col] = size(p);
for i = 1: 2: col
    p(:, i:i+1) = sort(p(:,i:i+1), 2);
end
p = unique(p, 'rows'); % remove the same row
% sort each row
[row, col] = size(p);
for i = 1: row
    temp = reshape(p(i,:), 2, col/2)';
    temp = sortrows(temp, 1);
    p(i,:) = reshape(temp', 1, col);
end
pairs = unique(p, 'rows'); % remove the same row

pairs =
    
         1     2     3     4     5     6
         1     2     3     5     4     6
         1     2     3     6     4     5
         1     3     2     4     5     6
         1     3     2     5     4     6
         1     3     2     6     4     5
         1     4     2     3     5     6
         1     4     2     5     3     6
         1     4     2     6     3     5
         1     5     2     3     4     6
         1     5     2     4     3     6
         1     5     2     6     3     4
         1     6     2     3     4     5
         1     6     2     4     3     5
         1     6     2     5     3     4

由于有人认为我以前的答案没有用,我发布了这个。

【讨论】:

  • 为什么要添加新答案而不是编辑现有答案?由于其他答案不起作用,正如 OP 所指出的,鉴于您发布了新答案,它可能应该被删除
  • 有人认为现有的没有用,我不想让我的新答案被误解。另外,我认为前者可以激励他人。
  • 这是一个问答网站,如果你的答案不正确,那就是多余的。阅读此页面的人会因为这个特定问题而这样做,而不是寻找灵感
  • 这有效,但仅适用于小 k。如果我想做 k=7,那么我的内存就会用完。理想情况下,希望直接生成对,而不是生成 (1,...,2k) 的所有排列并消除多余的排列。
  • @Raymond Kan 没错,当 k = 10 时,矩阵将为 654729075x10 (48.8GB)。当然,我可以根据perms 或nchoosek 的源代码编写一个新函数来直接生成对,但该函数只能在k
【解决方案2】:

我有以下列举配对的蛮力方法。不是特别有效。当 k>9 时也会导致内存问题。在这种情况下,我只能枚举但不能创建 Z 并将结果存储在其中。

function Z = pair2(k)
   count = [2*k-1:-2:3];
   tcount = prod(count);
   Z = zeros(tcount,2*k);
   x = [ones(1,k-2) 0];
   z = zeros(1,2*k);
   for i=1:tcount
       for j=k-1:-1:1
           if x(j)<count(j)
              x(j) = x(j)+1;
              break
            end
            x(j) = 1;
       end
       y = [1:2*k];
       for j=1:k-1
           z(2*j-1) = y(1);
           z(2*j) = y(x(j)+1);
           y([1 x(j)+1]) = [];
       end
       z(2*k-1:2*k) = y;
       Z(i,:) = z;
   end

【讨论】:

  • 不同分区的数量是(2n)!/(2^n * n!),它会随着n 快速增长——如果你有这个列表,你可能需要限制你想要做的事情的范围需要n&gt;9!
  • 我同意,我不应该存储分区,我可以枚举循环中的每种可能性并为该分区做必要的工作,然后继续下一个。这样,我可以做更大的 k,比如 k=12。
  • 这将有助于解决内存限制,但您很快就会遇到迭代超过循环的时间限制!
【解决方案3】:
k = 3;
set = 1: 2*k;
combos = combntns(set, k);
[len, ~] = size(combos);
pairs = [combos(1:len/2,:) flip(combos(len/2+1:end,:))];

pairs =
         
         1     2     3     4     5     6
         1     2     4     3     5     6
         1     2     5     3     4     6
         1     2     6     3     4     5
         1     3     4     2     5     6
         1     3     5     2     4     6
         1     3     6     2     4     5
         1     4     5     2     3     6
         1     4     6     2     3     5
         1     5     6     2     3     4

您也可以使用nchoosek 代替combntns。在combntns 或nchoosek 上查看更多信息

【讨论】:

  • 谢谢,但这并没有产生我需要的东西。共有 1x3x5 = 15 种不同的方式将 {1,2...,6} 分组为 3 对。例如,我也应该有 [1 6 2 3 4 5]
  • 对不起,我误解了你的问题。不过好像可以用`nchoosek'自己写一个函数来解决这个问题。我认为在 Stack Overflow 中,我们需要互相激励,提升自己,但不要沉迷于请求。至少你应该发布你的代码并证明你的尝试。
猜你喜欢
  • 2010-11-26
  • 2014-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-02
  • 2014-02-13
  • 2014-04-04
相关资源
最近更新 更多