我需要在[A..B]范围内生成2个随机数,但数量不能相邻。 我想在恒定的时间内完成它(我不想继续绘画,直到第二个值好)。
我可以想到几种方法:
[A..B-2]
中绘制V1,然后从范围[V1+2..B]
中绘制V2 [2..B-A]
绘制d,从[0..B-A-d]
绘制V1,然后V2=V1+d
[A+2-V1..B-V1-1]
中绘制d,并设置V2= d<=0 ? V1-2+d : V1+1+d
[A..B]
中选择V1,从[0..A-B-2]
中选择{,V2 = V1+d
; V2 = V2>B ? V2-(B-A)
我想要最随机的方法(生成大多数熵,具有最均匀的分布)。我认为最后两个是相同的,比前两个更随机。还有更好的方法吗?
答案 0 :(得分:4)
假设范围是[0, n)
。对于随机无序的非相邻对,只需从[0, n-2)
生成随机无序对,并将更大的元素增加2
即可。后者可以通过[0, (n+1)n/2)
的双射映射来实现。
import random
def randnonadjpair(n):
i, j = randunordpair(n-2)
return i, j+2
def randunordpair(n):
i = random.randrange((n+1)*n//2)
if n%2 == 1:
if i < n:
return i, n-1
i -= n
n -= 1
h = n//2
q, r = divmod(i, h)
if q < h:
return q, h + r
q -= h
if q <= r:
return q, r
return n-q, n-1-r
(这个答案适用于有序对。)
有2 (n-2) + (n-2) (n-3) = n^2 - 3 n + 2
种方法可以从长度为n
的范围中选择两个有序的非相邻元素。在x
包含和0
排除之间生成随机数n^2 - 3 n + 2
,然后将其双射地映射到有效结果:
def biject(n, x):
if x < n - 2:
return (0, x + 2)
x -= n - 2
if x < n - 2:
return (n - 1, x)
x -= n - 2
q, r = divmod(x, n - 3)
return (q, r if r < q - 1 else r + 3)
答案 1 :(得分:2)
如果你想要最大熵,那么你的两个选择必须是独立的。因此,第二个选择的价值不受第一个选择的限制;两者都必须从可用的整个范围中选择。这意味着独立选择两个数字,将它们作为一对进行检查,如果该对不合适则拒绝这两个数字。在伪代码中,它看起来像:
class A
{
int m;
static void print(std::ostream& stream, A x, int options)
{
stream << "Value is: " << (x.m * 1000000 + options);
}
}
您可以检查方法function pickPair()
repeat
num1 <- random(A, B)
num2 <- random(A, B)
until (notAdjacent(num1, num2))
return (num1, num2)
end function
中两个数字的约束。
您没有说明范围[A..B]的大小。给定一个相当大的范围,那么不得不拒绝一对的机会很低。或者,始终选择固定数量的对并返回符合您标准的任何对:
notAdjacent()
您需要设置足够的重复次数,以便在统计上确定找到有效的对。
答案 2 :(得分:0)
我会这样做:
V1
V1 == A || V1 == B
从[A..B-1]中抽取V2
,则从[A..B-2]中抽取V2
执行:
if(V2 >= V1 - 1) V2++;
if(V2 >= V1 + 1) V2++;
首次检查确保V1 - 1
不能是V2
的价值
第二项检查确保V1 + 1
不能是V2
的值
或者,换句话说,这会将值重新映射到[A..V1-2] [V1] [V1 + 2..B]。
由于这不会丢弃或重复任何值,因此分布应该很好。
此答案目前假定V1 == V2
有效。
击>
事实上,不,上述的分布会有偏见
如果N = B - A + 1
,
= A
或= B
,有N - 2
对包含[A+1...B-1]
中的数字,只有N - 3
对包含它。计算对M
的数量,在[1..M]
中绘制一个数字并将其映射回相应的对,详见David Eisenstats的答案。
答案 3 :(得分:0)
以下方法如何:
V1 = rand(A..B)
V2 = rand(A+2..B-1)
V2 += V2 > V1 ? 1 : -2
另外,应该提到的是,你不能在这里获得第二选择的均匀分布。
左侧和右侧的边框项目将有更多机会被选中。
内部数字的概率为(B-A-3)/(B-A)
,而边界元素的概率为(B-A-2)/(B-A)
。
答案 4 :(得分:0)
这是我目前的计划:
给定目标范围[A..B]
。它的长度L
是A-B+1
。我们希望选择V1,V2
,V2
不在[V1-1..V1+1]
范围内
如果V1
为A
,那么L-2
有V2
种可能性
如果V1
为A+1
,则L-3
有V2
种可能性
...
扩展此模式后,我们将P
的可能性总数设为sum([1..L-2])
。 (这是@David Eisenstat提出的数字的一半)。
如果我们在N
范围内选择一个[0,P)
,我们就可以生成相应的组合:
V1 = A
T = L-2
while (N >= T):
N -= T
T -= 1
V1 += 1
V2 = V2 + N + 2