如何在一个范围内生成2个不相邻的随机数

时间:2017-01-31 16:54:35

标签: algorithm random

我需要在[A..B]范围内生成2个随机数,但数量不能相邻。 我想在恒定的时间内完成它(我不想继续绘画,直到第二个值好)。

我可以想到几种方法:

  • 选择第一个,然后选择一个适合它的:从范围[A..B-2]中绘制V1,然后从范围[V1+2..B]中绘制V2
  • 选择它们之间的距离,然后放置它们:从[2..B-A]绘制d,从[0..B-A-d]绘制V1,然后V2=V1+d
  • 选择第一个,然后选择第二个偏移:从整个范围绘制V1,然后从范围[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)

我想要最随机的方法(生成大多数熵,具有最均匀的分布)。我认为最后两个是相同的,比前两个更随机。还有更好的方法吗?

5 个答案:

答案 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)

我会这样做:

  • 从[A..B]
  • 中抽取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]。它的长度LA-B+1。我们希望选择V1,V2V2不在[V1-1..V1+1]范围内 如果V1A,那么L-2V2种可能性 如果V1A+1,则L-3V2种可能性 ...
扩展此模式后,我们将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