假设你正在收集卡片-你的相册是由卡片组成的您购买的每一包包含n_cards
卡,每张卡都有相同的提取概率如果你不能换双打,你需要买多少包才能把所有的卡都收起来假设你想模拟这个过程这是一个显而易见的方法:
n_cards = 100; n_experiments = 1e4; cards_in_pack = 5;
cards = randi([1 n_cards], ceil(sqrt(n_cards)) * n_experiments * n_cards, 1, 'uint16');
tic
n_packs = zeros(n_experiments, 1);
ctrl1 = 1;
i_f = 0;
n = 0;
while ctrl1
ctrl2 = 1;
i1 = 0;
while ctrl2
i1 = i1 + 1;
ctrl2 = numel(unique(cards((cards_in_pack * i_f + 1):(cards_in_pack * (i_f + i1))))) ~= n_cards;
end
n = n + 1;
n_packs(n) = i1;
i_f = i_f + i1;
ctrl1 = n ~= n_experiments;
end
toc
% Average number of packs:
mean(n_packs)
% Distribution of the number of packs necessary to complete the album
hist(n_packs, 50)
% Number of cards needed in the experiments:
sum(n_packs) * cards_in_pack
这很慢-有没有更快的方法具体来说:在Matlab中有没有一种快速计算唯一值累积计数的方法?
最佳答案
仿真可以跨实验矢量化从而消除了实验回路,大大缩短了仿真时间。
由于每个实验可能在不同的时间完成(所需的包数不同),因此一个实验可以处于两种状态:进行中或完成代码维护一个正在进行的实验向量(exps_ongoing
)和每个实验(cards_obtained
)中获得的卡片的0-1矩阵。
对于每个正在进行的实验,都会生成一个新的包,并且包中包含的卡(over)会写在cards_obtained
上当一个正在进行的实验获得了所有卡片后,该实验将从exps_ongoing
中移除所有实验完成后,代码结束。
n_cards = 100;
cards_in_pack = 5;
n_experiments = 1e4;
cards_obtained = zeros(n_cards,n_experiments);
%// will contain cards obtained in each experiment
exps_ongoing = 1:n_experiments; %// list of which experiments are ongoing
n_packs = zeros(1,n_experiments); %// will record how many packs have been used
while ~isempty(exps_ongoing)
n_packs(exps_ongoing) = n_packs(exps_ongoing) + 1;
%// pick one pack for each ongoing experiment
new_cards = randi(n_cards,cards_in_pack,numel(exps_ongoing));
%// generate pack contents for each ongoing experiment
cards_obtained(new_cards + repmat(((exps_ongoing)-1)*n_cards,cards_in_pack,1)) = true;
%// take note of obtained cards in each ongoing experiment. Linear indexing is used here
exps_ongoing = setdiff(exps_ongoing,exps_ongoing(all(cards_obtained(:,exps_ongoing))));
%// ongoing experiments for which all cards have been obtained are removed
end
disp(mean(n_packs))
对于您的输入数据,这将使我的计算机上的时间减少50倍(104.36秒
与1.89秒相比,用
tic
,toc
测量)。