如何使排列矩阵更有效?

时间:2018-07-27 05:08:45

标签: matlab matrix permutation

我已经编写了这段代码:

a = repelem(ones(7,8)-2.*eye(7,8), 7:-1:1, 1);
for i=1:7
    a(i,i+1)=-1;
end
for i=8:13
    a(i,i-5)=-1;
end
for i=14:18
    a(i,i-10)=-1;
end
for i=19:22
    a(i,i-14)=-1;
end
for i=23:25
    a(i,i-17)=-1;
end
for i=26:27
    a(i,i-19)=-1;
end
for i=28:28
    a(i,i-20)=-1;
end

要生成此矩阵:

-1  -1   1   1   1   1   1   1
-1   1  -1   1   1   1   1   1
-1   1   1  -1   1   1   1   1
-1   1   1   1  -1   1   1   1
-1   1   1   1   1  -1   1   1
-1   1   1   1   1   1  -1   1
-1   1   1   1   1   1   1  -1
 1  -1  -1   1   1   1   1   1
 1  -1   1  -1   1   1   1   1
 1  -1   1   1  -1   1   1   1
 1  -1   1   1   1  -1   1   1
 1  -1   1   1   1   1  -1   1
 1  -1   1   1   1   1   1  -1
 1   1  -1  -1   1   1   1   1
 1   1  -1   1  -1   1   1   1
 1   1  -1   1   1  -1   1   1
 1   1  -1   1   1   1  -1   1
 1   1  -1   1   1   1   1  -1
 1   1   1  -1  -1   1   1   1
 1   1   1  -1   1  -1   1   1
 1   1   1  -1   1   1  -1   1
 1   1   1  -1   1   1   1  -1
 1   1   1   1  -1  -1   1   1
 1   1   1   1  -1   1  -1   1
 1   1   1   1  -1   1   1  -1
 1   1   1   1   1  -1  -1   1
 1   1   1   1   1  -1   1  -1
 1   1   1   1   1   1  -1  -1

我正在寻找一种更有效的方法来生成此矩阵。一种方法是:

S=[-1 -1 1 1 1 1 1 1];
P=unique(perms(S),'rows');

但是我根本不想使用置换,因为我想使用此代码并制作尺寸更大的矩阵,而使用置换使之不可能。

2 个答案:

答案 0 :(得分:2)

您将在{1乘8的1个向量中生成-1的2个值的每个排列。因此,您可以使用nchoosek生成-1值的列索引,然后使用sub2ind在单个索引步骤中修改矩阵a

indices = nchoosek(1:8, 2);
N = size(indices, 1);
a = ones(N, 8);
a(sub2ind([N 8], [1:N 1:N].', indices(:))) = -1;

输出:

a =

    -1    -1     1     1     1     1     1     1
    -1     1    -1     1     1     1     1     1
    -1     1     1    -1     1     1     1     1
    -1     1     1     1    -1     1     1     1
    -1     1     1     1     1    -1     1     1
    -1     1     1     1     1     1    -1     1
    -1     1     1     1     1     1     1    -1
     1    -1    -1     1     1     1     1     1
     1    -1     1    -1     1     1     1     1
     1    -1     1     1    -1     1     1     1
     1    -1     1     1     1    -1     1     1
     1    -1     1     1     1     1    -1     1
     1    -1     1     1     1     1     1    -1
     1     1    -1    -1     1     1     1     1
     1     1    -1     1    -1     1     1     1
     1     1    -1     1     1    -1     1     1
     1     1    -1     1     1     1    -1     1
     1     1    -1     1     1     1     1    -1
     1     1     1    -1    -1     1     1     1
     1     1     1    -1     1    -1     1     1
     1     1     1    -1     1     1    -1     1
     1     1     1    -1     1     1     1    -1
     1     1     1     1    -1    -1     1     1
     1     1     1     1    -1     1    -1     1
     1     1     1     1    -1     1     1    -1
     1     1     1     1     1    -1    -1     1
     1     1     1     1     1    -1     1    -1
     1     1     1     1     1     1    -1    -1

答案 1 :(得分:2)

@gnovice的答案非常好,但是我想为教学目的添加一个替代答案。正如gnovice所说,“您将在1乘8的1的向量中产生将-1的2个值定位的每个排列”。。我们可以通过考虑如何生成[-1 -1 1 1 1 1 1 1]的连续排列来解决这个问题。

来自C++,这非常直观,因为algorithm库提供了std::next_permutation,可生成向量的下一个lexicographical排列。该算法非常简单,可以在以下位置找到:https://en.cppreference.com/w/cpp/algorithm/next_permutation。实际上,Jos已在matlab中实现了该算法的更为通用的版本。我们将使用nextperm_local,该文件位于nextperm的文件交换页面上“功能”选项卡的最底部。

myP = [-1 -1 1 1 1 1 1 1];

function P = nextperm_local(P)
    k1 = find(P(2:end) > P(1:end-1), 1, 'last');
    if isempty(k1)
        k1 = 0;
    else
        k2 = find(P(k1)<P, 1, 'last');
        P([k1 k2]) = P([k2 k1]);
    end
    P((k1+1):end) = P(end:-1:(k1+1));
end

total = nchoosek(8, 2);
output = zeros(total, 8);

for i = 1:total
    output(i,:) = myP ;
    myP = nextperm_local(myP) ;
end

并生成以下矩阵:

output =

  -1  -1   1   1   1   1   1   1
  -1   1  -1   1   1   1   1   1
  -1   1   1  -1   1   1   1   1
  -1   1   1   1  -1   1   1   1
  -1   1   1   1   1  -1   1   1
  -1   1   1   1   1   1  -1   1
  -1   1   1   1   1   1   1  -1
   1  -1  -1   1   1   1   1   1
   1  -1   1  -1   1   1   1   1
   1  -1   1   1  -1   1   1   1
   1  -1   1   1   1  -1   1   1
   1  -1   1   1   1   1  -1   1
   1  -1   1   1   1   1   1  -1
   1   1  -1  -1   1   1   1   1
   1   1  -1   1  -1   1   1   1
   1   1  -1   1   1  -1   1   1
   1   1  -1   1   1   1  -1   1
   1   1  -1   1   1   1   1  -1
   1   1   1  -1  -1   1   1   1
   1   1   1  -1   1  -1   1   1
   1   1   1  -1   1   1  -1   1
   1   1   1  -1   1   1   1  -1
   1   1   1   1  -1  -1   1   1
   1   1   1   1  -1   1  -1   1
   1   1   1   1  -1   1   1  -1
   1   1   1   1   1  -1  -1   1
   1   1   1   1   1  -1   1  -1
   1   1   1   1   1   1  -1  -1