C++:创建唯一的随机分布 1000 次,在任何分布中都没有重复的数字
C++ : Create unique random distributions 1000 times with no repeated numbers in any distribution
问题:
我的数字范围是 1 到 20,000。我想从范围内采样 8 个不同数字的均匀分布,1000 次。每个分布不应有重复的数字。此外,1000 个分布中的每个分布都必须是唯一的(在对所有获得的分布进行字母排序后,没有两个分布在技术上应该是相同的数字序列)。
我做了什么:
我遇到了 C++ 11 标准中的 std::uniform_int_distribution<int>
。所以尝试了下面的代码来测试它在不同范围内的唯一性。
#include <iostream>
#include <random>
int main(int, char*[]) {
const int range_from = 0;
const int range_to = 20000;
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(range_from, range_to);
for(int i = 0; i < 1000; ++i){ //Iteration for maximum distributions
for (int j = 0; j < 8; ++j) //Iteration for random distribution generation
std::cout << distr(generator) << '\n';
}
}
不同尝试获得的输出
Attempt 1: Attempt 2:
16102 6656
540 10316
8718 12251
18059 1254
10976 3982
18391 12857
14748 9253
12137 3335
一些事实:
根据两次尝试,输出看起来是唯一的。我还意识到可以有 20,000C8 = 20,000!/(8!x19,992!) 这样可能唯一的分布(每个分布中没有相同的数字,并且当我们按字母顺序排序时没有重复分布)。
我的问题:
这段代码真的可以按照我目前的形式做我想做的事情吗?或者我应该做一些昂贵的验证过程,比如对每个分布进行字母排序,并将每个分布记录在 std::vector
中,并检查分布是否已经存在?
后一个过程非常昂贵并且需要大量的计算时间。您会建议任何 alternative/better 方法吗?
如果您希望 1000 组 8 个随机数是唯一的,那么您可以生成您想要的所有值,将它们随机化,然后从随机化组中取前 8000 个值作为您的 1000 组 8 个随机数。
int main()
{
const int range_from = 0;
const int range_to = 20000;
std::vector<int> values(range_to - range_from);
std::generate(values.begin(), values.end(), [value = range_from]() mutable { return value++; });
// values now has 0 to 20000
std::shuffle(values.begin(), values.end(), std::mt19937{std::random_device{}()});
// now it is a random order
values.resize(8000);
// now we have the 8000 random numbers in the range 0 to 20000
}
在这种情况下这并不太浪费,但如果您的范围足够大并且您想要的集合数量足够少,您可能需要选择其他解决方案。否则你会浪费很多 space.
问题:
我的数字范围是 1 到 20,000。我想从范围内采样 8 个不同数字的均匀分布,1000 次。每个分布不应有重复的数字。此外,1000 个分布中的每个分布都必须是唯一的(在对所有获得的分布进行字母排序后,没有两个分布在技术上应该是相同的数字序列)。
我做了什么:
我遇到了 C++ 11 标准中的 std::uniform_int_distribution<int>
。所以尝试了下面的代码来测试它在不同范围内的唯一性。
#include <iostream>
#include <random>
int main(int, char*[]) {
const int range_from = 0;
const int range_to = 20000;
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(range_from, range_to);
for(int i = 0; i < 1000; ++i){ //Iteration for maximum distributions
for (int j = 0; j < 8; ++j) //Iteration for random distribution generation
std::cout << distr(generator) << '\n';
}
}
不同尝试获得的输出
Attempt 1: Attempt 2:
16102 6656
540 10316
8718 12251
18059 1254
10976 3982
18391 12857
14748 9253
12137 3335
一些事实:
根据两次尝试,输出看起来是唯一的。我还意识到可以有 20,000C8 = 20,000!/(8!x19,992!) 这样可能唯一的分布(每个分布中没有相同的数字,并且当我们按字母顺序排序时没有重复分布)。
我的问题:
这段代码真的可以按照我目前的形式做我想做的事情吗?或者我应该做一些昂贵的验证过程,比如对每个分布进行字母排序,并将每个分布记录在 std::vector
中,并检查分布是否已经存在?
后一个过程非常昂贵并且需要大量的计算时间。您会建议任何 alternative/better 方法吗?
如果您希望 1000 组 8 个随机数是唯一的,那么您可以生成您想要的所有值,将它们随机化,然后从随机化组中取前 8000 个值作为您的 1000 组 8 个随机数。
int main()
{
const int range_from = 0;
const int range_to = 20000;
std::vector<int> values(range_to - range_from);
std::generate(values.begin(), values.end(), [value = range_from]() mutable { return value++; });
// values now has 0 to 20000
std::shuffle(values.begin(), values.end(), std::mt19937{std::random_device{}()});
// now it is a random order
values.resize(8000);
// now we have the 8000 random numbers in the range 0 to 20000
}
在这种情况下这并不太浪费,但如果您的范围足够大并且您想要的集合数量足够少,您可能需要选择其他解决方案。否则你会浪费很多 space.