如何在具有特定范围的行和列中重复生成随机矩阵
示例(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
答案 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)
假设您想要包含1
和n
之间的所有元素
%// 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