I am trying to solve this problem for an online judge:
There are sets of n men and n women. Each man evaluates the women with numbers from 1 to n, giving them different grades, and each woman estimates similarly to the men from 1 to n. This all leads to formation of pairs according to the principle of maximum attractiveness for both partners and calculation of the happiness coefficient. The coefficient of happiness is the sum of the man's evaluation and the evaluation of the woman.
You have to maximize the sum of the happiness coefficients of the pairs and to output these pairs.
Input:
The first line contains a natural n where 1 ≤ n ≤ 1000 – the quantity of people of the same sex.
The next n lines contain men’s evaluations for each of the women.
The final n lines for women are input analogically.
Output:
The first line should contain the maximal sum of the happiness coefficients of the pairs.
The second line should contain men’s partners successively (firstly, the partner for the first man, then the partner for the second man, and so on).
Example:
Input
3
1 2 3
2 3 1
1 2 3
1 2 3
2 3 1
3 1 2
Output
16
3 2 1
I have the following code:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
void stable_marriage(vector<vector<int>> &matrix) {
int n = matrix[0].size();
vector<int> status(n * 2, -1);/*status[i] contains husband/wife of i, initially -1*/
queue<int> q;
for (int i = 0; i < n; i++)/* Push all single men */
q.push(i);
/* While there is a single men */
while (!q.empty()) {
int i = q.front();
q.pop();
/* iterate through his preference list */
for (int j = 0; j < n; j++) {
/* if girl is single marry her to this man*/
if (status[matrix[i][j]] == -1) {
status[i] = matrix[i][j];/* set this girl as wife of i */
status[matrix[i][j]] = i;/*make i as husband of this girl*/
break;
}
else {
int rank_1, rank_2;/* for holding priority of current husband and most preferable husband*/
for (int k = 0; k < n; k++) {
if (matrix[matrix[i][j]][k] == status[matrix[i][j]])
rank_1 = k;
if (matrix[matrix[i][j]][k] == i)
rank_2 = k;
}
/* if current husband is less attractive
than divorce him and marry a new one making the old one
single */
if (rank_2 < rank_1) {/* if this girl j prefers current man i
more than her present husband */
status[i] = matrix[i][j];/* her wife of i */
int old = status[matrix[i][j]];
status[old] = -1;/*divorce current husband*/
q.push(old);/*add him to list of singles */
status[matrix[i][j]] = i;/* set new husband for this girl*/
break;
}
}
}
}
for (int i = n - 1; i >= 0; i--) {
cout << status[i] << ' ';
}
}
int main() {
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
int n;
cin >> n;
vector<vector<int>> matrix(n * 2, vector<int>(n));
for (int i = 0; i < n * 2; i++) {
for (int j = 0; j < n; j++) {
cin >> matrix[i][j];
}
}
stable_marriage(matrix);
return 0;
}
Now, what I don't get is that how the happiness coefficient is measured? I don't see how, can you help?
The problem states that the happiness for a couple is the sum of their evaluations for their respective partners. The value you are supposed to find is the maximum value of the sum of happiness for the n couples that can be formed with the given men and women.
For instance, for the sample input, the following pairings are possible.
A = (1, 1), (2, 2), (3, 3)
B = (1, 1), (2, 3), (3, 2)
C = (1, 2), (2, 1), (3, 3)
D = (1, 2), (2, 3), (3, 1)
E = (1, 3), (2, 2), (3, 1)
F = (1, 3), (2, 1), (3, 2)
As you can confirm by manually calculating their evaluations of one another, the following are the sums that can be obtained for each scenario.
A = ( 2 + 6 + 5 ) = 13
B = ( 2 + 2 + 3 ) = 7
C = ( 4 + 4 + 5 ) = 13
D = ( 4 + 2 + 4 ) = 10
E = ( 6 + 6 + 4 ) = 16
F = ( 6 + 4 + 3 ) = 13
As you can see, the maximum amount of total happiness that can be achieved is 16, as given in the sample output.
For example, 16 can be expressed in these ways:
2*2*2*2
4*2*2
4*4
8*2
(excluding the trivial case 1*16)
36:
2*2*3*3
2*2*9
2*18
4*3*3
12*3
4*9
Therefore, I need to find all the representations of any given number just like above.
To start, I was able to come up with all the divisors of a given number with the codes below:
void FindDivisors(int n)
{
vector<int> my_vector;
for (int i = 2; i < n/2 + 1; i++)
{
if (n % i == 0)
my_vector.push_back(i); //store divisors in a vector.
}
}
After this, I got stuck. How do I get from all the divisors to all the factorizations wanted?
I can think of a recursion method that seems to work but do not exactly know how to implement it:
Take 16 as the example. Let's name the function to find all the representations of n to be "Factor(n)". All non-trivial divisors of 16 are {2,4,8}. We divide 16 by each of its divisor and get {8, 4, 2}. Then Factor(16) = the union of 2*Factor(8), 4*Factor(4) and 8*Factor(8). However, this is as far as I got. I am new to recursion and not sure if this route works out. I need some help on how to put things together.
As long as you don't know the number of factors, the most effective solution is recursion.
You will need a vector to store the current path:
vector<int> path; // it will store all current factors
and a recursive function.
For every iteration you try to divide current remainder and remember:
void OutputRec(int value)
{
if (value == 1) // We have divided the whole number
{
for (int i = 0; i < path.size(); i++) cout << path[i] << " ";
cout << endl;
return;
}
for (int i = value; i > 1; i--)
{
if (value % i == 0) { // if it is divisible
path.push_back(i); // add to path
OutputRec(i, value / i); // continue working
path.pop_back(); // remove from path
}
}
}
void Output(int value)
{
cout << "Result for " << value << ": " << endl;
path = vector<int>();
OutputRec(value);
}
int main() {
Output(4);
Output(16);
Output(36);
Output(256);
return 0;
}
For example, let we have 8. Here is how it works:
OutputRec(8), path = []:
i = 8: divisible (8 / 1 = 1)
OutputRec(1), path = [8], value == 1 > output "8".
i = 7, 6, 5: not divisible
i = 4: divisible (8 / 4 = 2)
OutputRec(2), path = [4]:
i2 = 2: divisible (2 / 2 = 1)
OutputRec(1), path = [4 2], value == 1 > output "4 2".
i = 3: not divisible
i = 2: divisible (8 / 2 = 4)
OutputRec(4), path = [2]:
i3 = 4: divisible (4 / 4 = 1)
OutputRec(1), path = [2 4], value == 1 > output "2 4".
i3 = 3: not divisible
i3 = 2: divisible (4 / 2 = 2)
OutputRec(2), path = [2 2]:
i4 = 2: divisible (2 / 2 = 1)
OutputRec(1), path = [2 2 2], value == 1 > output "2 2 2"
Result:
8,
4 * 2,
2 * 4,
2 * 2 * 2
Now, you see the problem: [2 4] and [4 2] is duplicated answer. How can we avoid duplicating answers? The easiest approach is to output values only in ascending (descending, does not matter) order.
Let's add max variable and store the last number inserted into a path and find only those dividers which are less or equal to it.
For example, if current path is [2], then the recursion shouldn't go for [2 4], but should go for [2 2]. The initial value of max is equal to value as the first number in the path can be any.
void OutputRec(int max, int value)
{
if (value == 1) {
for (int i = 0; i < path.size(); i++) cout << path[i] << " ";
if (path.size() == 1) cout << "1";
cout << endl;
return;
}
for (int i = max; i > 1; i--) // loop from max. Min(max, value) would be better
{
if (value % i == 0) {
path.push_back(i);
OutputRec(i, value / i);
path.pop_back();
}
}
}
void Output(int value)
{
cout << "Result for " << value << ": " << endl;
path = vector<int>();
OutputRec(value, value);
}
Here is how it works now:
OutputRec(8), path = []:
i = 8: divisible (8 / 8 = 1)
OutputRec(1), path = [8], value == 1 > output "8".
i = 7, 6, 5: not divisible
i = 4: divisible (8 / 4 = 2)
OutputRec(2), path = [4]:
i2 = 2: divisible
OutputRec(1), path = [4 2], value == 1 > output "4 2".
i = 3: not divisible
i = 2: divisible (8 / 2 = 4)
OutputRec(4), path = [2]:
// notice i3 starts from 2, because last inserted is 2
i3 = 2: divisible (4 / 2 = 2)
OutputRec(2), path = [2 2]:
i4 = 2: divisible (2 / 2 = 1)
OutputRec(1), path = [2 2 2], value == 1 > output "2 2 2"
Result:
8,
4 * 2,
2 * 2 * 2
Everything works fine! The only thing which looks incorrect is "8". It probably should be "8 * 1". You can add a line like if (path.size() == 1) cout << "1"; to the output.
Result:
8 * 1,
4 * 2,
2 * 2 * 2
Here is the working Ideone demo.
I hope that I didn't confuse you even more. It is really difficult to explain what recursion is at the first time.
Recursion is like swimming or cycling - it looks difficult first. Then, you try it and learn it, and once you understand it - you will wonder why couldn't you do this before :) Good luck.
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;
}