如何生成随机数,使其总和等于给定数?

时间:2014-01-15 00:39:57

标签: c++ algorithm random sum max

我想生成X个随机数,每个都来自<0; Y>区间(给定Y作为每个数字的最大值),但是这些数字的总和必须等于{ {1}}。

实施例: 5个Randoms数字,每个最大值6和总和必须等于14,例如:Z

是否已经有可以做类似的C / C ++功能?

就我个人而言,我无法想出一些丑陋的if-else-constucts。

4 个答案:

答案 0 :(得分:2)

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

#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

答案 1 :(得分:1)

注意:当问题指定“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';
    }
}

答案 2 :(得分:0)

#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测试了它,它和我一起工作 希望这是你要求的

答案 3 :(得分:0)

LiHo的回答与我的第二个建议非常相似,所以我会离开,但这是第一个例子。它可能会得到改善,但它不应该有任何悲剧性的错误。 Here's a live sample.

#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);
    minNum = std::min(maxNum, std::max(minNum, MAX - maxNum * (LINES - i)));

    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);

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

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