容易,吝啬,以正确的方式观看.
您希望生成n对整数[p,q],使得p和q位于间隔[1,m]中,p
有多少对可能?总数只是m *(m-1)/ 2. (即,从1到m-1的数字之和)
所以我们可以在[1,m *(m-1)/ 2]的范围内生成n个随机整数.兰德尔做得很好. (旧的matlab版本不允许第二个参数为randperm.)
k = randperm(m/2*(m-1),n);
(注意,我用一个有趣的方式写了这个表达式,除以2可能是一个奇怪的地方,这避免了在上限附近的某些值的精度问题.)
现在,如果我们将每个可能的对[p,q]与k中的一个整数相关联,我们可以从k中生成的整数向后工作到一对[p,q].因此,该列表中的前几个对是:
{[1,2], [1,3], [2,3], [1,4], [2,4], [3,4], ..., [m-1,m]}
我们可以把它们看作是m的严格上三角阵列中的元素,这些元素在主对角线之上.
q = floor(sqrt(8*(k-1) + 1)/2 + 1/2);
p = k - q.*(q-1)/2;
看到这些公式从k中展开的元素中恢复p和q.我们可以说服自己确实有效,但也许这里只是一个简单的方法:
k = 1:21;
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
[k;p;q]'
ans =
1 1 2
2 1 3
3 2 3
4 1 4
5 2 4
6 3 4
7 1 5
8 2 5
9 3 5
10 4 5
11 1 6
12 2 6
13 3 6
14 4 6
15 5 6
16 1 7
17 2 7
18 3 7
19 4 7
20 5 7
21 6 7
测试它的另一种方式是显示所有的对都是为小案例生成的.
m = 5;
n = 10;
k = randperm(m/2*(m-1),n);
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
sortrows([p;q]',[2 1])
ans =
1 2
1 3
2 3
1 4
2 4
3 4
1 5
2 5
3 5
4 5
嗯,看起来一切都很完美.现在尝试一些大量的m和n来测试所用的时间.
tic
m = 1e6;
n = 100000;
k = randperm(m/2*(m-1),n);
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
toc
Elapsed time is 0.014689 seconds.
该方案对于m大致为1e8,在由于双精度的精度误差而失败之前将起作用.在m / 2 *(m-1)超过2 ^ 53之前,精确极限应该不大于134217728.一个很好的功能是,不需要对重复对进行拒绝.