如何产生随机数,使它们的和等于给定的数



我想产生X个随机数,每个随机数都来自区间<0; Y>(给定Y为每个数的最大值),但有一个限制,即这些数的和必须等于Z

示例:5个随机数,每个最大值为6,总和必须等于14,例如:0, 2, 6, 4, 2

是否已经有一个C/C++函数可以做类似的事情?

就我个人而言,我只能想出一些丑陋的建筑。

由于不需要生成的序列是统一的,这可能是一种可能的解决方案:

#include <iostream>
#include <vector>
#include <cstdlib>
int irand(int min, int max) {
return ((double)rand() / ((double)RAND_MAX + 1.0)) * (max - min + 1) + min;
}
int main()
{
int COUNT = 5,    // X
MAX_VAL = 6,  // Y
MAX_SUM = 14; // Z
std::vector<int> buckets(COUNT, 0);
srand(time(0));
int remaining = MAX_SUM;
while (remaining > 0)
{
int rndBucketIdx = irand(0, COUNT-1);
if (buckets[rndBucketIdx] == MAX_VAL)
continue;                       // this bucket is already full
buckets[rndBucketIdx]++;
remaining--;
}
std::cout << "Printing sequence: "; 
for (size_t i = 0; i < COUNT; ++i)
std::cout << buckets[i] << ' ';
}

它只是简单地将总和除以一堆桶,直到它消失:)

输出示例:Printing sequence: 4 4 1 0 5

注意:此解决方案是在问题指定"MAX SUM"参数时编写的,这意味着小于该金额的总和也是可以接受的。这个问题现在已经根据OP的评论进行了编辑,他们的意思是累计金额必须真正达到目标。我不打算更新这个答案,但很明显,它可能会在最后一级递归中丢弃较少的总数。

该解决方案使用解决输入标准的所有可能的数字组合对vector<vector<int>>进行一次性总体,然后每次需要新的解决方案时,它都会随机选择其中一个,并将数字打乱为随机顺序(从而选择组合的排列)。

它有点重——可能不适合我开始写它后你提到的实际用途-P-但它会产生偶数加权分布,并且您可以轻松地执行一些操作,例如保证在所有其他组合都返回之前不会再次返回组合(在组合中使用支持的索引洗牌向量)。

#include <iostream>
#include <vector>
#include <algorithm>
using std::min;
using std::max;
using std::vector;
// print solutions...    
void p(const vector<vector<int>>& vvi)
{
for (int i = 0; i < vvi.size(); ++i)
{
for (int j = 0; j < vvi[i].size(); ++j)
std::cout << vvi[i][j] << ' ';
std::cout << 'n';
}
}
// populate results with solutions...
void f(vector<vector<int>>& results, int n, int max_each, int max_total)
{
if (n == 0) return;
if (results.size() == 0)
{
for (int i = 0; i <= min(max_each, max_total); ++i)
results.push_back(vector<int>(2, i));
f(results, n - 1, max_each, max_total);
return;
}
vector<vector<int>> new_results;
for (int r = 0; r < results.size(); ++r)
{
int previous = *(results[r].rbegin() + 1);
int current_total = results[r].back();
int remaining = max_total - current_total;
for (int i = 0; i <= min(previous,min(max_each, remaining)); ++i)
{
vector<int> v = results[r];
v.back() = i;
v.push_back(current_total + i);
new_results.push_back(v);
}
}
results = new_results;
f(results, n - 1, max_each, max_total);
}
const vector<int>& once(vector<vector<int>>& solutions)
{
int which = std::rand() % solutions.size();
vector<int>& v = solutions[which];
std::random_shuffle(v.begin(), v.end() - 1);
return v;
}
int main()
{
vector<vector<int>> solutions;
f(solutions, 5, 6, 14);
std::cout << "All solution combinations...n";
p(solutions);
std::cout << "------------------n";
std::cout << "A few sample permutations...n";
for (int n = 1; n <= 100; ++n)
{
const vector<int>& o = once(solutions);
for (int i = 0; i < o.size() - 1; ++i)
std::cout << o[i] << ' ';
std::cout << 'n';
}
}
#include<iostream>
#include <cstdlib> //rand ()
using namespace std;
void main()
{
int random ,x=5;
int max , totalMax=0 , sum=0;
cout<<"Enter the total maximum number : ";
cin>>totalMax;
cout<<"Enter the maximum number: ";
cin>>max;
srand(0);
for( int i=0; i<x ; i++)
{
random=rand()%max+1; //range from 0 to max
sum+=random;
if(sum>=totalMax)
{
sum-=random;
i--;
}
else
cout<<random<<' ';
}
cout<<endl<<"Reached total maximum number "<<totalMax<<endl; 

}

我写了这个简单的代码
我用totalMax=14和max=3测试了它,它对我很有效希望这是你对的要求

LiHo的答案看起来与我的第二个建议非常相似,所以我不谈了,但这里是第一个建议的例子。它可能可以改进,但不应该有任何悲剧性的错误。这是一个活样本。

#include <algorithm>
#include <array>
#include <random>
std::random_device rd;
std::mt19937 gen(rd());
constexpr int MAX = 14;
constexpr int LINES = 5;
int sum{};
int maxNum = 6;
int minNum{};
std::array<int, LINES> nums;
for (int i = 0; i < LINES; ++i) {
maxNum = std::min(maxNum, MAX - sum);
// e.g., after 0 0, min is 2 because only 12/14 can be filled after
int maxAfterThis = maxNum * (LINES - i - 1);
minNum = std::min(maxNum, std::max(minNum, MAX - sum - maxAfterThis));

std::uniform_int_distribution<> dist(minNum, maxNum);
int num = dist(gen);

nums[i] = num;
sum += num;
}
std::shuffle(std::begin(nums), std::end(nums), gen);

每次创建这种分布可能会减慢速度(我不知道),但范围必须在构造函数中,我不能说这些数字的分布有多好。然而,逻辑非常简单。除此之外,它还使用了漂亮、闪亮的C++11<random>标头。

我们只是确保没有剩余的数字超过MAX(14),并且在最后达到MAXminNum是一个奇怪的部分,这取决于它的进展。它从零开始,并根据需要向上移动(std::max的第二部分是弄清楚如果我们得到6秒的剩余时间,需要什么),但我们不能让它超过maxNum。如果minNum存在的话,我愿意用一种更简单的方法来计算它。

既然你知道你需要多少个数字,就从给定的分布中生成它们,但不需要进一步的条件,存储它们,计算实际的和,并将它们全部放大/缩小以获得所需的和。

最新更新