簡體   English   中英

如何產生隨機數,使它們的和等於給定數?

[英]How to produce random numbers so that their sum is equal to given number?

我想產生X個隨機數,每個隨機數的間隔均<0; Y> <0; Y> (給定每個數字的最大值Y ),但是存在限制,即這些數字的總和必須等於Z

實施例:5個隨機量的數字,每個最大6和的總和必須等於14,例如: 0, 2, 6, 4, 2

已經有可以執行類似操作的C / C ++函數嗎?

就我個人而言,我只能提出一些丑陋的if-else-constructs構想。

由於不需要統一的生成順序,因此這可能是以下解決方案之一:

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

每次創建該分配都有可能減慢它的速度(我不知道),但是范圍必須在構造函數中進行,我不是要說這些數字的分布情況如何。 但是,邏輯很簡單。 除此之外,它還使用了漂亮的,閃亮的C ++ 11 <random>標頭。

我們只是確保沒有剩余數超過MAX (14),並且在最后達到MAX minNum是奇數部分,這是由於它如何進行。 它從零開始,然后根據需要向上增加( std::max的第二部分正在弄清楚如果剩下的6s會需要什么),但是我們不能讓它超過maxNum 我願意考慮一個更簡單的計算minNum方法(如果存在)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM