A prime p is fixed. A sequence of n numbers is given, each from 1 to p - 1. It is known that the numbers in the sequence are chosen randomly, equally likely and independently from each other. Choose some numbers from the sequence so that their product, taken modulo p, is equal to the given number x. If no numbers are selected, the product is considered equal to one.
Input:
The first line contains three integers separated by spaces: the length of the sequence n, the prime number p and the desired value x
(n=100, 2<=p<=10^9, 0<x<p)
Next, n integers are written, separated by spaces or line breaks: the sequence a1, a2,. . ., an
(0 <ai <p)
Output:
Print the numbers from the sequence whose product modulo p is equal to x. The order in which numbers are displayed is not important. If there are several possible answers, print any of them
Example:
INPUT:
100 11 4
9 6 1 1 10 4 9 10 3 1 10 1 6 8 3 3 9 8
10 3 7 7 1 3 3 1 5 2 10 4 1 5 6 7 2 6
2 8 3 3 6 7 6 3 1 5 10 2 2 10 9 6 8 6
2 10 3 2 7 4 3 2 8 6 4 1 7 2 10 8 4 9
7 9 8 7 4 7 3 2 8 2 3 7 1 5 2 10 7 1 8
6 4 10 10 3 6 10 2 1
OUTPUT:
4 6 10 9
My solution:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n,p,x,y,m,k,tmp;
vector<int> v;
cin >> n >> p >> x;
for (int i = 0; i<n; i++){
cin >> tmp;
v.push_back(tmp);
}
sort(v.begin(), v.end());
v.erase(v.begin(), upper_bound(v.begin(), v.end(), 1));
k=-1;
while(1){
k++;
m = 1;
y = x+p*k;;
vector<int> res;
for (int i = 0; i<n; i++){
if (y == 1) break;
if ( y%v[i] == 0){
res.push_back(v[i]);
m*=v[i];
m%=p;
y = y/v[i];
}
}
if (m==x) {
for (int i = 0; i<res.size(); i++){
cout << res[i] << " ";
}
break;
}
}
return 0;
}
In my solution, I used condition (y=x+k*p, where y is the product of numbers in the answer, and k is some kind of natural number). And also iterated over the value k.
This solution sometimes goes beyond the allotted time. Please tell me a more correct algorithm.
I would consider a backtracking routine over the hashed multiset of the input list. Since p is a prime, at any point we can consider if the current multiple, m, has (multiplicative_inverse(m, p) * x) % p in our multiset (https://en.wikipedia.org/wiki/Multiplicative_inverse). If it exists, we're done. Otherwise, try multiplying either by the same number we are currently visiting in the multiset, or by the next one (keep the result of the multiplication modulo p).
Please see comment below for a link to example code in Python. The example you gave has trivial solutions so it would be helpful to have some non-trivial, as well as challenging examples to test and refine on. Please also clarify if more than one number is expected in the output.
You can use dynamic programming approach. It requires O(p) memory cells and O(p*n) loop iterations. There is possible several optimization (to exclude processing input duplicates, or print longest/shortest selection chain). Following is simplest and basic DP-program, demonstrating this approach.
#include <stdio.h>
#include <stdlib.h>
int data[] = {
9, 6, 1, 1, 10, 4, 9, 10, 3, 1, 10, 1, 6, 8, 3, 3, 9, 8,
10, 3, 7, 7, 1, 3, 3, 1, 5, 2, 10, 4, 1, 5, 6, 7, 2, 6,
2, 8, 3, 3, 6, 7, 6, 3, 1, 5, 10, 2, 2, 10, 9, 6, 8, 6,
2, 10, 3, 2, 7, 4, 3, 2, 8, 6, 4, 1, 7, 2, 10, 8, 4, 9,
7, 9, 8, 7, 4, 7, 3, 2, 8, 2, 3, 7, 1, 5, 2, 10, 7, 1, 8,
6, 4, 10, 10, 3, 6, 10, 2, 1
};
struct elm {
int val; // Value
int prev; // from which elemet we come to this
int n; // add loop cound for prevent multiple use same val
};
void printsol(int n, int p, int x, const int *in) {
struct elm *dp = (struct elm *)calloc(p, sizeof(struct elm));
int i, j;
for(i = 0; i < n; i++) // add initial elements into DP array
dp[in[i]].val = in[i];
for(i = 0; i < n; i++) { // add elements, one by one, to DP array
if(dp[in[i]].val <= 1) // skip secondary "1" multipliers
continue;
for(j = 1; j < p; j++)
if(dp[j].val != 0 && dp[j].n < i) {
int y = ((long)j * in[i]) % p;
dp[y].val = in[i]; // current value, for printout
dp[y].prev = j; // reference to prev element
dp[y].n = n; // loop num, for prevent double reuse
if(x == y && dp[x].n > 0) {
// targed reached - print result, by iterate linklist
int mul = 1;
while(x != 0) {
printf(" %d ", dp[x].val);
mul *= dp[x].val; mul %= p;
x = dp[x].prev;
}
printf("; mul=%d\n", mul);
free(dp);
return;
}
} // for+if
} // for i
free(dp);
}
int main(int argc, char **argv) {
printsol(100, 11, 4, data);
return 0;
}
I am working on a project which need to find a certain number in a two dimensional array(a matrix) .the visiting order of matrix order is like this (4*4 matrix). Now I stand in the position 0. Equivalently, I want to visit the matrix element in diagonal firstly.
0 2 7 14
3 1 5 12
8 6 4 10
15 13 11 9
Besides, how to break two nest loop in c++ while do not use goto statement.
The following code will traverse a square matrix of any size, with priority on the diagonal
#define SIZE 4
static int test[SIZE][SIZE] =
{
{ 0, 2, 7, 14 },
{ 3, 1, 5, 12 },
{ 8, 6, 4, 10 },
{ 15, 13, 11, 9 }
};
int main( void )
{
int diagonal, delta;
for ( diagonal = 0; diagonal < SIZE; diagonal++ )
{
cout << test[diagonal][diagonal] << endl;
for ( delta = 1; delta <= diagonal; delta++ )
{
cout << test[diagonal-delta][diagonal] << endl;
cout << test[diagonal][diagonal-delta] << endl;
}
}
}
Here's one way to break out of a nested loop without a goto
done = false;
for ( i = 0; i < 10; i++ )
{
for ( j = 0; j < 10; j++ )
{
if ( some_condition_is_met )
{
done = true;
break;
}
}
if ( done )
break;
}
Use another array with array indices (since the size of your array is probably constant anyway), for instance, if you stored first array in one dimensional c++ array, then
int actual_arr[16];
int indices[16] = {0, 5, 1, 4, 10, 6, 9, 2, 8, 15, 11, 14, 7, 13, 3, 12 };
So then you can write a loop:
for (int i = 0; i < 16; ++i)
{
actual_arr[indices[i]]++;
}
So every field in indices is an index of actual_arr which will be visited at this point.
You can do it with two dimensional representation, too, if it required. Just replace int indices[16] with std::pair<int, int> indices[16] and you're good to go.
Especially when you have a fixed-size array and visit it many times, this is good solution, since it doesn't involve any computation in the loop.
Btw. As a sidenote, mathematically speaking, the indices array would be called a permutation and can be an operation in permutations group.
To move to the element on the right, you increment a row.
To move to the element on the left, you decrement a row.
To move to the element below, you increment a column.
To move to the element above, you decrement the column.
Now to move diagonally, observe how the row and columns change and apply a combination of the above.
There are n people numbered from 1 to n. I have to write a code which produces and print all different combinations of k people from these n. Please explain the algorithm used for that.
I assume you're asking about combinations in combinatorial sense (that is, order of elements doesn't matter, so [1 2 3] is the same as [2 1 3]). The idea is pretty simple then, if you understand induction / recursion: to get all K-element combinations, you first pick initial element of a combination out of existing set of people, and then you "concatenate" this initial element with all possible combinations of K-1 people produced from elements that succeed the initial element.
As an example, let's say we want to take all combinations of 3 people from a set of 5 people. Then all possible combinations of 3 people can be expressed in terms of all possible combinations of 2 people:
comb({ 1 2 3 4 5 }, 3) =
{ 1, comb({ 2 3 4 5 }, 2) } and
{ 2, comb({ 3 4 5 }, 2) } and
{ 3, comb({ 4 5 }, 2) }
Here's C++ code that implements this idea:
#include <iostream>
#include <vector>
using namespace std;
vector<int> people;
vector<int> combination;
void pretty_print(const vector<int>& v) {
static int count = 0;
cout << "combination no " << (++count) << ": [ ";
for (int i = 0; i < v.size(); ++i) { cout << v[i] << " "; }
cout << "] " << endl;
}
void go(int offset, int k) {
if (k == 0) {
pretty_print(combination);
return;
}
for (int i = offset; i <= people.size() - k; ++i) {
combination.push_back(people[i]);
go(i+1, k-1);
combination.pop_back();
}
}
int main() {
int n = 5, k = 3;
for (int i = 0; i < n; ++i) { people.push_back(i+1); }
go(0, k);
return 0;
}
And here's output for N = 5, K = 3:
combination no 1: [ 1 2 3 ]
combination no 2: [ 1 2 4 ]
combination no 3: [ 1 2 5 ]
combination no 4: [ 1 3 4 ]
combination no 5: [ 1 3 5 ]
combination no 6: [ 1 4 5 ]
combination no 7: [ 2 3 4 ]
combination no 8: [ 2 3 5 ]
combination no 9: [ 2 4 5 ]
combination no 10: [ 3 4 5 ]
From Rosetta code
#include <algorithm>
#include <iostream>
#include <string>
void comb(int N, int K)
{
std::string bitmask(K, 1); // K leading 1's
bitmask.resize(N, 0); // N-K trailing 0's
// print integers and permute bitmask
do {
for (int i = 0; i < N; ++i) // [0..N-1] integers
{
if (bitmask[i]) std::cout << " " << i;
}
std::cout << std::endl;
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}
int main()
{
comb(5, 3);
}
output
0 1 2
0 1 3
0 1 4
0 2 3
0 2 4
0 3 4
1 2 3
1 2 4
1 3 4
2 3 4
Analysis and idea
The whole point is to play with the binary representation of numbers
for example the number 7 in binary is 0111
So this binary representation can also be seen as an assignment list as such:
For each bit i if the bit is set (i.e is 1) means the ith item is assigned else not.
Then by simply computing a list of consecutive binary numbers and exploiting the binary representation (which can be very fast) gives an algorithm to compute all combinations of N over k.
The sorting at the end (of some implementations) is not needed. It is just a way to deterministicaly normalize the result, i.e for same numbers (N, K) and same algorithm same order of combinations is returned
For further reading about number representations and their relation to combinations, permutations, power sets (and other interesting stuff), have a look at Combinatorial number system , Factorial number system
PS: You may want to check out my combinatorics framework Abacus which computes many types of combinatorial objects efficiently and its routines (originaly in JavaScript) can be adapted easily to many other languages.
If the number of the set would be within 32, 64 or a machine native primitive size, then you can do it with a simple bit manipulation.
template<typename T>
void combo(const T& c, int k)
{
int n = c.size();
int combo = (1 << k) - 1; // k bit sets
while (combo < 1<<n) {
pretty_print(c, combo);
int x = combo & -combo;
int y = combo + x;
int z = (combo & ~y);
combo = z / x;
combo >>= 1;
combo |= y;
}
}
this example calls pretty_print() function by the dictionary order.
For example. You want to have 6C3 and assuming the current 'combo' is 010110.
Obviously the next combo MUST be 011001.
011001 is :
010000 | 001000 | 000001
010000 : deleted continuously 1s of LSB side.
001000 : set 1 on the next of continuously 1s of LSB side.
000001 : shifted continuously 1s of LSB to the right and remove LSB bit.
int x = combo & -combo;
this obtains the lowest 1.
int y = combo + x;
this eliminates continuously 1s of LSB side and set 1 on the next of it (in the above case, 010000 | 001000)
int z = (combo & ~y)
this gives you the continuously 1s of LSB side (000110).
combo = z / x;
combo >> =1;
this is for 'shifted continuously 1s of LSB to the right and remove LSB bit'.
So the final job is to OR y to the above.
combo |= y;
Some simple concrete example :
#include <bits/stdc++.h>
using namespace std;
template<typename T>
void pretty_print(const T& c, int combo)
{
int n = c.size();
for (int i = 0; i < n; ++i) {
if ((combo >> i) & 1)
cout << c[i] << ' ';
}
cout << endl;
}
template<typename T>
void combo(const T& c, int k)
{
int n = c.size();
int combo = (1 << k) - 1; // k bit sets
while (combo < 1<<n) {
pretty_print(c, combo);
int x = combo & -combo;
int y = combo + x;
int z = (combo & ~y);
combo = z / x;
combo >>= 1;
combo |= y;
}
}
int main()
{
vector<char> c0 = {'1', '2', '3', '4', '5'};
combo(c0, 3);
vector<char> c1 = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
combo(c1, 4);
return 0;
}
result :
1 2 3
1 2 4
1 3 4
2 3 4
1 2 5
1 3 5
2 3 5
1 4 5
2 4 5
3 4 5
a b c d
a b c e
a b d e
a c d e
b c d e
a b c f
a b d f
a c d f
b c d f
a b e f
a c e f
b c e f
a d e f
b d e f
c d e f
a b c g
a b d g
a c d g
b c d g
a b e g
a c e g
b c e g
a d e g
b d e g
c d e g
a b f g
a c f g
b c f g
a d f g
b d f g
c d f g
a e f g
b e f g
c e f g
d e f g
In Python, this is implemented as itertools.combinations
https://docs.python.org/2/library/itertools.html#itertools.combinations
In C++, such combination function could be implemented based on permutation function.
The basic idea is to use a vector of size n, and set only k item to 1 inside, then all combinations of nchoosek could obtained by collecting the k items in each permutation.
Though it might not be the most efficient way require large space, as combination is usually a very large number. It's better to be implemented as a generator or put working codes into do_sth().
Code sample:
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
int main(void) {
int n=5, k=3;
// vector<vector<int> > combinations;
vector<int> selected;
vector<int> selector(n);
fill(selector.begin(), selector.begin() + k, 1);
do {
for (int i = 0; i < n; i++) {
if (selector[i]) {
selected.push_back(i);
}
}
// combinations.push_back(selected);
do_sth(selected);
copy(selected.begin(), selected.end(), ostream_iterator<int>(cout, " "));
cout << endl;
selected.clear();
}
while (prev_permutation(selector.begin(), selector.end()));
return 0;
}
and the output is
0 1 2
0 1 3
0 1 4
0 2 3
0 2 4
0 3 4
1 2 3
1 2 4
1 3 4
2 3 4
This solution is actually a duplicate with
Generating combinations in c++
Here is an algorithm i came up with for solving this problem. You should be able to modify it to work with your code.
void r_nCr(const unsigned int &startNum, const unsigned int &bitVal, const unsigned int &testNum) // Should be called with arguments (2^r)-1, 2^(r-1), 2^(n-1)
{
unsigned int n = (startNum - bitVal) << 1;
n += bitVal ? 1 : 0;
for (unsigned int i = log2(testNum) + 1; i > 0; i--) // Prints combination as a series of 1s and 0s
cout << (n >> (i - 1) & 1);
cout << endl;
if (!(n & testNum) && n != startNum)
r_nCr(n, bitVal, testNum);
if (bitVal && bitVal < testNum)
r_nCr(startNum, bitVal >> 1, testNum);
}
You can see an explanation of how it works here.
I have written a class in C# to handle common functions for working with the binomial coefficient, which is the type of problem that your problem falls under. It performs the following tasks:
Outputs all the K-indexes in a nice format for any N choose K to a file. The K-indexes can be substituted with more descriptive strings or letters. This method makes solving this type of problem quite trivial.
Converts the K-indexes to the proper index of an entry in the sorted binomial coefficient table. This technique is much faster than older published techniques that rely on iteration. It does this by using a mathematical property inherent in Pascal's Triangle. My paper talks about this. I believe I am the first to discover and publish this technique.
Converts the index in a sorted binomial coefficient table to the corresponding K-indexes. I believe it is also faster than the other solutions.
Uses Mark Dominus method to calculate the binomial coefficient, which is much less likely to overflow and works with larger numbers.
The class is written in .NET C# and provides a way to manage the objects related to the problem (if any) by using a generic list. The constructor of this class takes a bool value called InitTable that when true will create a generic list to hold the objects to be managed. If this value is false, then it will not create the table. The table does not need to be created in order to perform the 4 above methods. Accessor methods are provided to access the table.
There is an associated test class which shows how to use the class and its methods. It has been extensively tested with 2 cases and there are no known bugs.
To read about this class and download the code, see Tablizing The Binomial Coeffieicent.
It should be pretty straight forward to port the class over to C++.
The solution to your problem involves generating the K-indexes for each N choose K case. For example:
int NumPeople = 10;
int N = TotalColumns;
// Loop thru all the possible groups of combinations.
for (int K = N - 1; K < N; K++)
{
// Create the bin coeff object required to get all
// the combos for this N choose K combination.
BinCoeff<int> BC = new BinCoeff<int>(N, K, false);
int NumCombos = BinCoeff<int>.GetBinCoeff(N, K);
int[] KIndexes = new int[K];
BC.OutputKIndexes(FileName, DispChars, "", " ", 60, false);
// Loop thru all the combinations for this N choose K case.
for (int Combo = 0; Combo < NumCombos; Combo++)
{
// Get the k-indexes for this combination, which in this case
// are the indexes to each person in the problem set.
BC.GetKIndexes(Loop, KIndexes);
// Do whatever processing that needs to be done with the indicies in KIndexes.
...
}
}
The OutputKIndexes method can also be used to output the K-indexes to a file, but it will use a different file for each N choose K case.
This templated function works with the vector of any type as an input.
Combinations are returned as a vector of vectors.
/*
* Function return all possible combinations of k elements from N-size inputVector.
* The result is returned as a vector of k-long vectors containing all combinations.
*/
template<typename T> std::vector<std::vector<T>> getAllCombinations(const std::vector<T>& inputVector, int k)
{
std::vector<std::vector<T>> combinations;
std::vector<int> selector(inputVector.size());
std::fill(selector.begin(), selector.begin() + k, 1);
do {
std::vector<int> selectedIds;
std::vector<T> selectedVectorElements;
for (int i = 0; i < inputVector.size(); i++) {
if (selector[i]) {
selectedIds.push_back(i);
}
}
for (auto& id : selectedIds) {
selectedVectorElements.push_back(inputVector[id]);
}
combinations.push_back(selectedVectorElements);
} while (std::prev_permutation(selector.begin(), selector.end()));
return combinations;
}
You can use the "count_each_combination" and "for_each_combination" functions from the combinations library from Howard Hinnant to generate all the combinations for take k from n.
#include <vector>
#include "combinations.h"
std::vector<std::vector<u_int8_t> >
combinationsNoRepetitionAndOrderDoesNotMatter (long int subsetSize, std::vector<uint8_t> setOfNumbers)
{
std::vector<std::vector<u_int8_t> > subsets{};
subsets.reserve (count_each_combination (setOfNumbers.begin (), setOfNumbers.begin () + subsetSize, setOfNumbers.end ()));
for_each_combination (setOfNumbers.begin (), setOfNumbers.begin () + subsetSize, setOfNumbers.end (), [&subsets] (auto first, auto last) {
subsets.push_back (std::vector<uint8_t>{ first, last });
return false;
});
return subsets;
}
int main(){
combinationsNoRepetitionAndOrderDoesNotMatter (6, { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 });
}
Benchmark on a Intel(R) Core(TM) i5-8600K CPU # 3.60GHz:
g++
benchmark name samples iterations estimated
mean low mean high mean
std dev low std dev high std dev
-------------------------------------------------------------------------------
combinations no repetition and
order does not matter 6 from 36 100 1 10.2829 s
92.5451 ms 92.3971 ms 92.9411 ms
1.15617 ms 532.604 us 2.48342 ms
clang++
benchmark name samples iterations estimated
mean low mean high mean
std dev low std dev high std dev
-------------------------------------------------------------------------------
combinations no repetition and
order does not matter 6 from 36 100 1 11.0786 s
88.1275 ms 87.8212 ms 89.3204 ms
2.82107 ms 400.665 us 6.67526 ms
Behind the link below is a generic C# answer to this problem: How to format all combinations out of a list of objects. You can limit the results only to the length of k pretty easily.
https://stackoverflow.com/a/40417765/2613458
It can also be done using backtracking by maintaining a visited array.
void foo(vector<vector<int> > &s,vector<int> &data,int go,int k,vector<int> &vis,int tot)
{
vis[go]=1;
data.push_back(go);
if(data.size()==k)
{
s.push_back(data);
vis[go]=0;
data.pop_back();
return;
}
for(int i=go+1;i<=tot;++i)
{
if(!vis[i])
{
foo(s,data,i,k,vis,tot);
}
}
vis[go]=0;
data.pop_back();
}
vector<vector<int> > Solution::combine(int n, int k) {
vector<int> data;
vector<int> vis(n+1,0);
vector<vector<int> > sol;
for(int i=1;i<=n;++i)
{
for(int i=1;i<=n;++i) vis[i]=0;
foo(sol,data,i,k,vis,n);
}
return sol;
}
I thought my simple "all possible combination generator" might help someone, i think its a really good example for building something bigger and better
you can change N (characters) to any you like by just removing/adding from string array (you can change it to int as well). Current amount of characters is 36
you can also change K (size of the generated combinations) by just adding more loops, for each element, there must be one extra loop. Current size is 4
#include<iostream>
using namespace std;
int main() {
string num[] = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z" };
for (int i1 = 0; i1 < sizeof(num)/sizeof(string); i1++) {
for (int i2 = 0; i2 < sizeof(num)/sizeof(string); i2++) {
for (int i3 = 0; i3 < sizeof(num)/sizeof(string); i3++) {
for (int i4 = 0; i4 < sizeof(num)/sizeof(string); i4++) {
cout << num[i1] << num[i2] << num[i3] << num[i4] << endl;
}
}
}
}}
Result
0: A A A
1: B A A
2: C A A
3: A B A
4: B B A
5: C B A
6: A C A
7: B C A
8: C C A
9: A A B
...
just keep in mind that the amount of combinations can be ridicules.
--UPDATE--
a better way to generate all possible combinations would be with this code, which can be easily adjusted and configured in the "variables" section of the code.
#include<iostream>
#include<math.h>
int main() {
//VARIABLES
char chars[] = { 'A', 'B', 'C' };
int password[4]{0};
//SIZES OF VERIABLES
int chars_length = sizeof(chars) / sizeof(char);
int password_length = sizeof(password) / sizeof(int);
//CYCKLE TROUGH ALL OF THE COMBINATIONS
for (int i = 0; i < pow(chars_length, password_length); i++){
//CYCKLE TROUGH ALL OF THE VERIABLES IN ARRAY
for (int i2 = 0; i2 < password_length; i2++) {
//IF VERIABLE IN "PASSWORD" ARRAY IS THE LAST VERIABLE IN CHAR "CHARS" ARRRAY
if (password[i2] == chars_length) {
//THEN INCREMENT THE NEXT VERIABLE IN "PASSWORD" ARRAY
password[i2 + 1]++;
//AND RESET THE VERIABLE BACK TO ZERO
password[i2] = 0;
}}
//PRINT OUT FIRST COMBINATION
std::cout << i << ": ";
for (int i2 = 0; i2 < password_length; i2++) {
std::cout << chars[password[i2]] << " ";
}
std::cout << "\n";
//INCREMENT THE FIRST VERIABLE IN ARRAY
password[0]++;
}}
To make it more complete, the following answer covers the case that the data set contains duplicate values. The function is written close to the style of std::next_permutation() so that it is easy to follow up.
template< class RandomIt >
bool next_combination(RandomIt first, RandomIt n_first, RandomIt last)
{
if (first == last || n_first == first || n_first == last)
{
return false;
}
RandomIt it_left = n_first;
--it_left;
RandomIt it_right = n_first;
bool reset = false;
while (true)
{
auto it = std::upper_bound(it_right, last, *it_left);
if (it != last)
{
std::iter_swap(it_left, it);
if (reset)
{
++it_left;
it_right = it;
++it_right;
std::size_t left_len = std::distance(it_left, n_first);
std::size_t right_len = std::distance(it_right, last);
if (left_len < right_len)
{
std::swap_ranges(it_left, n_first, it_right);
std::rotate(it_right, it_right+left_len, last);
}
else
{
std::swap_ranges(it_right, last, it_left);
std::rotate(it_left, it_left+right_len, n_first);
}
}
return true;
}
else
{
reset = true;
if (it_left == first)
{
break;
}
--it_left;
it_right = n_first;
}
}
return false;
}
The full data set is represented in the range [first, last). The current combination is represented in the range [first, n_first) and the range [n_first, last) holds the complement set of the current combination.
As a combination is irrelevant to its order, [first, n_first) and [n_first, last) are kept in ascending order to avoid duplication.
The algorithm works by increasing the last value A on the left side by swapping with the first value B on the right side that is greater than A. After the swapping, both sides are still ordered. If no such value B exists on the right side, then we start to consider increasing the second last on the left side until all values on the left side are not less than the right side.
An example of drawing 2 elements from a set by the following code:
std::vector<int> seq = {1, 1, 2, 2, 3, 4, 5};
do
{
for (int x : seq)
{
std::cout << x << " ";
}
std::cout << "\n";
} while (next_combination(seq.begin(), seq.begin()+2, seq.end()));
gives:
1 1 2 2 3 4 5
1 2 1 2 3 4 5
1 3 1 2 2 4 5
1 4 1 2 2 3 5
1 5 1 2 2 3 4
2 2 1 1 3 4 5
2 3 1 1 2 4 5
2 4 1 1 2 3 5
2 5 1 1 2 3 4
3 4 1 1 2 2 5
3 5 1 1 2 2 4
4 5 1 1 2 2 3
It is trivial to retrieve the first two elements as the combination result if needed.
The basic idea of this solution is to mimic the way you enumerate all the combinations without repetitions by hand in high school. Let com be List[int] of length k and nums be List[int] the given n items, where n >= k.
The idea is as follows:
for x[0] in nums[0,...,n-1]
for x[1] in nums[idx_of_x[0] + 1,..,n-1]
for x[2] in nums [idx_of_x[1] + 1,...,n-1]
..........
for x[k-1] in nums [idx_of_x[k-2]+1, ..,n-1]
Obviously, k and n are variable arguments, which makes it impossible to write explicit multiple nested for-loops. This is where the recursion comes to rescue the issue.
Statement len(com) + len(nums[i:]) >= k checks whether the remaining unvisited forward list of items can provide k iitems. By forward, I mean you should not walk the nums backward for avoiding the repeated combination, which consists of same set of items but in different order. Put it in another way, in these different orders, we can choose the order these items appear in the list by scaning the list forward. More importantly, this test clause internally prunes the recursion tree such that it only contains n choose k recursive calls. Hence, the running time is O(n choose k).
from typing import List
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
assert 1 <= n <= 20
assert 1 <= k <= n
com_sets = []
self._combine_recurse(k, list(range(1, n+1)), [], com_sets)
return com_sets
def _combine_recurse(self, k: int, nums: List[int], com: List[int], com_set: List[List[int]]):
"""
O(C_n^k)
"""
if len(com) < k:
for i in range(len(nums)):
# Once again, don't com.append() since com should not be global!
if len(com) + len(nums[i:]) >= k:
self._combine_recurse(k, nums[i+1:], com + [nums[i]], com_set)
else:
if len(com) == k:
com_set.append(com)
print(com)
sol = Solution()
sol.combine(5, 3)
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 3, 4]
[1, 3, 5]
[1, 4, 5]
[2, 3, 4]
[2, 3, 5]
[2, 4, 5]
[3, 4, 5]
Try this:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void combo(vector<char> &alphabet, int n, vector<string> &result, string curr) {
if (n == 0) {
result.push_back(curr);
return;
}
for (int i = 0; i < alphabet.size(); i++) {
combo(alphabet, n - 1, result, curr + alphabet[i]);
}
return;
}
int main() {
//N items
vector<char> alphabet = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n','o','p','q','r','s','t','u','v','w','x','y','z'};
vector<string> result;
//K is 4
combo(alphabet, 4, result, "");
for (auto s : result) {
cout << s << endl;
}
return 0;
}