[英]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.