So I N - numbers I have to input, and I got M - numbers of places for those numbers and I need to find all combinations with repetition of given numbers.
Here is example:
Let's say that N is 3(I Have to input 3 numbers), and M is 4.
For example let's input numbers: 6 11 and 533.
This should be result
6,6,6,6
6,6,6,11
6,6,6,533
6,6,11,6
...
533,533,533,533
I know how to do that manualy when I know how much is N and M:
In example where N is 3 and M is 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;
}
But how can I make algorithm so I can enter N and M via std::cin and I get correct resut?
Thanks.
First one short tip: don't use "new" or C-style arrays in C++ when we have RAII and much faster data structures.
For the solution to your problem I would suggest making separate function with recursion. You said you know how to do it manually so the first step in making it into algorithm is to tear down you manual solution step by step. For this problem when you solve it by hand you basically start with array of all first numbers and then for last position you just loop through available numbers. Then you go to the second last position and again loop through available numbers just now with the difference that for every number there you must also repeat the last spot number loop. Here is the recursion. For every "n"th position you must loop through available numbers and for every call the same function for "n+1"th number.
Here is a simplified solution, leaving out the input handling and exact print to keep code shorter and more focused on the problem:
#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;
}
If you have any questions feel free to ask.
Totally there is no need for recursion here. This is a typical job for dynamic programming. Just get the first solution right for n = 1 (1 slot is available) which means the answer is [[6],[11],[533]]
and then move on one by one by relying on the one previously memoized solution.
Sorry that i am not fluent in C, yet in JS this is the solution. I hope it helps.
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)));
Normally the easiest way to do dynamic nested for loops is to create your own stack and use recursion.
#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});
}
output
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
Here is an algorithm to solve this, that does't use recursion.
Let's say n=2 and m=3. Consider the following sequence that corresponds to these values:
000
001
010
011
100
101
110
111
The meaning of this is that when you see a 0 you take the first number, and when you see a 1 you take the second number. So given the input numbers [5, 7], then 000 = 555, 001=557, 010=575 etc.
The sequence above looks identical to representing numbers from 0 to 7 in base 2. Basically, if you go from 0 to 7 and represent the numbers in base 2, you have the sequence above.
If you take n=3, m=4 then you need to work in base 3:
0000
0001
0002
0010
0011
0012
....
So you go over all the numbers from 0 to 63 (4^3-1), represent them in base 3 and follow the coding: 0 = first number, 1 = second number, 2 = third number and 3 = fourth number.
For the general case, you go from 0 to M^N-1, represent each number in base N, and apply the coding 0 = first number, etc.
Here is some sample code:
#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;
}
Output:
000
001
010
011
100
101
110
111