【发布时间】:2014-03-25 16:22:20
【问题描述】:
我有以下问题:
从 0-N 范围内生成 M 个均匀随机整数,其中 N >> M,并且没有一对的差值小于 K。其中 M >> K。
目前我能想到的最好的方法是维护一个排序列表,然后确定当前生成的整数的下限,并用上下元素测试它,如果可以,则在两者之间插入元素.这是 O(nlogn) 的复杂度。
会不会有更高效的算法?
问题的一个例子:
生成1000个0到1亿之间的均匀随机整数,其中任意两个整数之差不小于1000
解决此问题的综合方法是:
- 确定满足约束条件的所有 n-choose-m 组合,我们称之为集合 X
- 在 [0,|X|) 范围内选择一个均匀随机整数 i。
- 从 X 中选择第 i 个组合作为结果。
当 n-choose-m 很大时,这个解决方案是有问题的,因为枚举和存储所有可能的组合将非常昂贵。因此寻求一种高效的在线生成解决方案。
注意:以下是pentadecagon
提供的解决方案的C++实现std::vector<int> generate_random(const int n, const int m, const int k)
{
if ((n < m) || (m < k))
return std::vector<int>();
std::random_device source;
std::mt19937 generator(source());
std::uniform_int_distribution<> distribution(0, n - (m - 1) * k);
std::vector<int> result_list;
result_list.reserve(m);
for (int i = 0; i < m; ++i)
{
result_list.push_back(distribution(generator));
}
std::sort(std::begin(result_list),std::end(result_list));
for (int i = 0; i < m; ++i)
{
result_list[i] += (i * k);
}
return result_list;
}
.
【问题讨论】:
-
分布应该如何?有固定数量的可能结果。所有这些都应该具有相同的概率吗?
-
@Heuster:'分布应该如何?'均匀分布。
-
我认为您的示例无效,因为 1000 >> 1000 不正确。
-
(@DavidEisenstat 如果我错了,请纠正我,我认为这应该可行:) 对包含
0和N - (M - 1)*K + K之间数字的数组进行 Fisher-Yates 洗牌,取最后K结果数组的数字。这为您提供了上述间隔的大小K的均匀随机子集。您可以使用它来构建整数N - (M - 1)*K的K + 1组合,方法是将K子集用作N - (M - 1)*K的一元表示中的逗号(参见here 以了解说明)。 -
@G.Bach 它可能会起作用,但是边界条件可能又会出现问题。你能仔细写下来并作为答案发布吗? (顺便说一下,有更多节省空间的方法来生成随机子集。)
标签: c++ algorithm random constraints unique