如何在行和列中不重复生成随机矩阵?

时间:2014-10-07 18:39:20

标签: matlab random matrix

如何在具有特定范围的行和列中重复生成随机矩阵

示例(3x3):范围1到3

2 1 3
3 2 1
1 3 2

示例(4x4):范围1到4

4 1 3 2
1 3 2 4
3 2 4 1
2 4 1 3

4 个答案:

答案 0 :(得分:4)

解决这个问题的一种方法是生成一个圆形矩阵并将其混洗。

mat_size = 4    
A = gallery('circul', 1:mat_size);                   % circular matrix
B = A( randperm(length(A)) , randperm(length(A)) );  % shuffle rows and columns with randperm

它给出了

A =
 1     2     3     4
 4     1     2     3
 3     4     1     2
 2     3     4     1

B =
 3     4     1     2
 2     3     4     1
 4     1     2     3
 1     2     3     4

这种方法应该很快。一个11大小的问题计算在0.047021秒。

答案 1 :(得分:1)

假设您想要包含1n之间的所有元素

,此算法将会发挥作用
%// Elements to be contained, but no zero allowed
a = [1 2 3 4];
%// all possible permutations and its size
n = numel(a);

%// initialization
output = zeros(1,n);
ii = 1;

while ii <= n;

    %// random permuation of input vector
    b = a(randperm(n));
    %// concatenate with already found values
    temp = [output; b];

    %// check if the row chosen in this iteration already exists
    if ~any( arrayfun(@(x) numel(unique(temp(:,x))) < ii+1, 1:n) )
        %// if not, append
        output = temp;
        %// increase counter
        ii = ii+1;
    end
end

output = output(2:end,:) %// delete first row with zeros

它绝对不是最快的实施方式。我很想看到其他人。 计算时间呈指数增长。但是高达7x7的一切都是可以承受的。

答案 2 :(得分:1)

我写了另一段代码(有趣的是比较时间,如果可能的话,让它并行)。还有perms的问题(需要重启Matlab才能生成11个元素,我有x64和16GB的内存)。比我决定保留字符而不是数字,减少矩阵占用的内存。当然,它会生成所有排列,我在开始时将它们混洗,在循环中以新的随机顺序进行选择。它以这种方式运行得更快,并且“吃”。记忆力减少结果显示11 x 11的时间(当然,它与运行不同)。

clear all;
t = cputime;

sze = 11;
variations = perms(char(1 : sze)); % permutations
varN = length(variations);
variations = variations(randperm(varN)', :); % shuffle
sudoku = zeros(sze, sze);
sudoku(1, :) = variations(1, :); % set the first row
indx = 2;

for ii = 2 : varN
    % take a random index 
    rowVal = variations(ii, :);
    % check that row numbers do not present in table at
    % corresponding columns
    if (~isempty(find(repmat(rowVal, sze, 1) - sudoku == 0, 1)))
        continue;
    end;
    sudoku(indx, :) = rowVal;
    disp(['Found row ' num2str(indx)]);
    indx = indx + 1;
    if indx > sze, break; end;
end;

disp(cputime - t);
disp(sudoku);

结果

  252.9712 seconds

     7    11     3     9     6     2     4     1     8    10     5
     1     9     6     3    10     7    11     5     2     4     8
     9     6    11     8     2    10     1     7     4     5     3
     4    10     7    11     1     8     5     2     6     3     9
     2     5     9     1     3     6     8     4    10     7    11
    10     3     5     6     7     4     2     9    11     8     1
     6     4     2    10     8     5     3    11     9     1     7
     3     8    10     4    11     1     7     6     5     9     2
    11     1     8     5     4     9     6     3     7     2    10
     5     2     4     7     9     3    10     8     1    11     6
     8     7     1     2     5    11     9    10     3     6     4

答案 3 :(得分:0)

这是一种节省内存的方法。花费的时间是随机的,但不是很大。所有可能的输出矩阵都是可能的。

这通过随机填充矩阵直到没有更多位置可用或直到整个矩阵被填充为止。代码被评论,因此它应该是显而易见的。

对于大小11,这需要几千或几万次尝试。在我的旧笔记本电脑上,这意味着从几秒到几十秒的(随机)运行时间。

也许可以使用uint8值代替double加速。不过,我不认为这会带来很大的收获。

代码:

clear all
n = 11; %// matrix size
[ ii jj ] = ndgrid(1:n); %// rows and columns of S
ii = ii(:);
jj = jj(:);
success = 0; %// ...for now
attempt = 0; %// attempt count (not really needed)
while ~success
    attempt = attempt + 1;
    S = NaN(n, n); %// initiallize result. NaN means position not filled yet
    t = 1; %// number t is being placed within S ...
    u = 1; %// ... for the u-th time
    mask = true(1, numel(ii)); %// initiallize mask of available positions
    while any(mask) %// while there are available positions
        available = find(mask); %// find available positions
        r = randi(numel(available), 1); %// pick one available position
        itu = ii(available(r)); %// row of t, u-th time 
        jtu = jj(available(r)); %// col of t, u-th time
        S(itu, jtu) = t; %// store t at that position
        remove = (ii==itu) | (jj==jtu);
        mask(remove) = false; %// update mask of positions available for t
        u = u+1; %// next u
        if u > n %// we are done with number t
            t = t+1; %// let's go with new t
            u = 1; %// initiallize u
            mask = isnan(S(:)); %// initiallize mask for this t
        end
        if t > n %// we are done with all numbers
            success = 1; %// exit outer loop (inner will be exited too)
        end
    end
end
disp(attempt) %// display number of attempts
disp(S) %// show result

示例结果:

10    11     8     9     7     2     3     4     1     6     5
 8     4     2     1    10    11     6     5     7     9     3
 2     3     5     6    11     8     1    10     4     7     9
 9     8     7     4     6    10    11     3     5     1     2
 3     5     9     8     2     1     4     7     6    11    10
11     9     4     5     3     6     2     1     8    10     7
 1     2     6     3     8     7     5     9    10     4    11
 7     1    11    10     5     4     9     8     2     3     6
 4     7     1     2     9     3    10     6    11     5     8
 6    10     3    11     1     5     7     2     9     8     4
 5     6    10     7     4     9     8    11     3     2     1