繁体   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