问题
For my experiment I have 20 categories which contain 9 pictures each. I want to show these pictures in a pseudo-random sequence where the only constraint to randomness is that one image may not be followed directly by one of the same category. So I need something similar to
r = randi([1 20],1,180);
just with an added constraint of two numbers not directly following each other. E.g.
14 8 15 15 7 16 6 4 1 8 is not legitimate, whereas
14 8 15 7 15 16 6 4 1 8 would be.
An alternative way I was thinking of was naming the categories A,B,C,...T, have them repeat 9 times and then shuffle the bunch. But there you run into the same problem I think? I am an absolute Matlab beginner, so any guidance will be welcome.
回答1:
The following uses modulo operations to make sure each value is different from the previous one:
m = 20; %// number of categories
n = 180; %// desired number of samples
x = [randi(m)-1 randi(m-1, [1 n-1])];
x = mod(cumsum(x), m) + 1;
How the code works
- In the third line, the first entry of
x
is a random value between0
andm-1
. Each subsequent entry represents the change that, modulom
, will give the next value (this is done in the fourth line). - The key is to choose that change between
1
andm-1
(not between0
andm-1
), to assure consecutive values will be different. In other words, given a value, there arem-1
(notm
) choices for the next value. - After the modulo operation,
1
is added to to transform the range of resulting values from0
,...,m-1
to1
,...,m
.
Test
Take all (n-1
) pairs of consecutive entries in the generated x
vector and count occurrences of all (m^2
) possible combinations of values:
count = accumarray([x(1:end-1); x(2:end)].', 1, [m m]);
imagesc(count)
axis square
colorbar
The following image has been obtained for m=20; n=1e6;
. It is seen that all combinations are (more or less) equally likely, except for pairs with repeated values, which never occur.
回答2:
You could look for the repetitions in an iterative manner and put new set of integers from the same group [1 20]
only into those places where repetitions have occurred. We continue to do so until there are no repetitions left -
interval = [1 20]; %// interval from where the random integers are to be chosen
r = randi(interval,1,180); %// create the first batch of numbers
idx = diff(r)==0; %// logical array, where 1s denote repetitions for first batch
while nnz(idx)~=0
idx = diff(r)==0; %// logical array, where 1s denote repetitions for
%// subsequent batches
rN = randi(interval,1,nnz(idx)); %// new set of random integers to be placed
%// at the positions where repetitions have occured
r(find(idx)+1) = rN; %// place ramdom integers at their respective positions
end
来源:https://stackoverflow.com/questions/26844396/matlab-array-of-random-integers-with-no-direct-repetition