簡體   English   中英

給定數字與重復的組合算法? C ++

[英]Algorithm for Combinations of given numbers with repetition? C++

因此,IN-我必須輸入的數字,而我得到M-這些數字的位數,我需要找到所有重復給定數字的組合。

這是示例:

假設N為3(我必須輸入3個數字),M為4。例如,讓我們輸入數字:6 11和533。這應該是結果

6,6,6,6

6,6,6,11

6,6,6,533

6,6,11,6

...

533533533533

當我知道N和M多少時,我知道如何手動進行操作:

在示例中,N為3,M為4:

int main(){

int N = 3;
int M = 4;

int *numbers = new int[N + 1];

for (int i = 0; i < N; i++)
    cin >> numbers[i];

for (int a = 0; a < N; a++)
    for (int b = 0; b < N; b++)
        for (int c = 0; c < N; c++)
            for (int d = 0; d < N; d++)
            {
                cout << numbers[a] << " " << numbers[b] << " " << numbers[c] << " " << numbers[d] << endl;
            }
return 0;

}

但是我該如何制定算法,以便可以通過std :: cin輸入N和M並得到正確的結果?

謝謝。

完全沒有必要在這里進行遞歸。 這是動態編程的典型工作。 只需為n = 1獲得第一個解決方案(有1個插槽可用),這意味着答案為[[6],[11],[533]] ,然后依靠先前記憶的解決方案一個接一個地前進。

抱歉,我不懂C語言,但是在JS中,這是解決方案。 希望對您有所幫助。

 function combosOfN(a,n){ var res = {}; for(var i = 1; i <= n; i++) res[i] = res[i-1] ? res[i-1].reduce((r,e) => r.concat(a.map(n => e.concat(n))),[]) : a.map(e => [e]); return res[n]; } var arr = [6,11,533], n = 4; console.log(JSON.stringify(combosOfN(arr,n))); 

通常,進行動態嵌套for循環的最簡單方法是創建自己的堆棧並使用遞歸。

#include <iostream>
#include <vector>

void printCombinations(int sampleCount, const std::vector<int>& options, std::vector<int>& numbersToPrint) {
    if (numbersToPrint.size() == sampleCount) {
       // got all the numbers we need, print them.
       for (int number : numbersToPrint) {
           std::cout << number << " ";
       }
       std::cout << "\n";
    }
    else {
        // Add a new number, iterate over all possibilities
        numbersToPrint.push_back(0);
        for (int number : options) {
            numbersToPrint.back() = number;
            printCombinations(sampleCount, options, numbersToPrint);
        } 
        numbersToPrint.pop_back();
    }
}


void printCombinations(int sampleCount, const std::vector<int>& options)     {
    std::vector<int> stack;
    printCombinations(sampleCount, options, stack);
}


int main()
{
  printCombinations(3, {1,2,3});
}

產量

1 1 1 
1 1 2 
1 1 3 
1 2 1 
1 2 2 
1 2 3 
1 3 1 
1 3 2 
1 3 3 
2 1 1 
2 1 2 
2 1 3 
2 2 1 
2 2 2 
2 2 3 
2 3 1 
2 3 2 
2 3 3 
3 1 1 
3 1 2 
3 1 3 
3 2 1 
3 2 2 
3 2 3 
3 3 1 
3 3 2 
3 3 3 

這是一種解決此問題的算法,它不使用遞歸。

假設n = 2和m = 3。 請考慮以下與這些值相對應的順序:

000001010110110100101110111

其含義是,當您看到0時,您將使用第一個數字,而當您看到1時,您將使用第二個數字。 因此,給定輸入數字[5,7],則000 = 555、001 = 557、010 = 575等。

上面的序列看起來與代表以2為底的0到7的數字相同。基本上,如果您從0到7代表以2為底的數字,則具有上面的序列。

如果取n = 3,m = 4,則需要以3為基數工作:0000 0001 0002 0010 0011 0012 ....

因此,您遍歷了從0到63(4 ^ 3-1)的所有數字,以基數3表示它們,並遵循以下編碼:0 =第一個數字,1 =第二個數字,2 =第三個數字和3 =第四個數字。

對於一般情況,您從0到M ^ N-1,以N為底數表示每個數字,然后應用編碼0 =第一個數字,依此類推。

這是一些示例代碼:

#include <stdio.h>
#include <math.h>

void convert_to_base(int number, char result[], int base, int number_of_digits) {
    for (int i = number_of_digits - 1; i >= 0; i--) {
        int remainder = number % base;
        number = number / base;
        result[i] = '0' + remainder;
    }
}


int main() {
    int n = 2, m = 3;

    int num = pow(n, m) - 1;
    for (int i = 0; i <= num; i++) {
        char str[33];

        convert_to_base(i, str, n, m);
        printf("%s\n", str);
    }

    return 0;
}

輸出:

000
001
010
011
100
101
110
111

第一個簡短提示:擁有RAII和更快的數據結構時,請不要在C ++中使用“新”或C樣式的數組。

對於您的問題的解決方案,我建議使用遞歸功能。 您說您知道如何手動執行,因此使其成為算法的第一步是逐步拆除手動解決方案。 對於這個問題,當您手動解決時,基本上是從所有第一個數字組成的數組開始,然后對於最后一個位置,只需遍歷可用數字即可。 然后,您轉到倒數第二個位置,並再次循環遍歷所有可用數字,不同之處在於,對於每個數字,您還必須重復最后一個點號循環。 這是遞歸。 對於第n個位置,您必須遍歷可用數字,並且對於每個調用,第n + 1個數字均應使用相同的功能。

這是一個簡化的解決方案,省去了輸入處理和精確的打印,以使代碼更短並且更專注於該問題:

#include <vector>
#include <iostream>

void printCombinations(const std::vector<int>& numbers, unsigned size, std::vector<int>& line) {
    for (unsigned i = 0; i < numbers.size(); i++) {
        line.push_back(numbers[i]);
        if (size <= 1) { // Condition that prevents infinite loop in recursion
            for (const auto& j : line)
                std::cout << j << ","; // Simplified print to keep code shorter
            std::cout << std::endl;
            line.erase(line.end() - 1);
        } else {
            printCombinations(numbers, size - 1, line); // Recursion happens here
            line.erase(line.end() - 1);
        }
    }
}

int main() {
    std::vector<int> numbers = {6, 11, 533};
    unsigned size = 4;
    std::vector<int> line;
    printCombinations(numbers, size, line);
    return 0;
}

如果你有任何問題隨時問。

暫無
暫無

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

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