What's the problem with the code below? - c++

#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
int i, s, g;
vector<int> a;
cin >> s;
for(i=1;i<=s;i++)
{
g = s;
if(g<10) a.push_back(g);
else {
vector<int> temp;
while(g > 0)
{
int k = g % 10;
g = g / 10;
temp.push_back(g);
}
for(int j=temp.size();j>0;j--)
{
a.push_back(temp[j]);
}
}
}
cout << a[s-1] << endl;
return 0;
}
What is wrong with the code above ? It doesn't give me the appropriate results.
The vector a is supposed to hold the values from 1, 2, 3...up to s such that a = 12345..910111213... and print to output a[s]. Ex if s=15 a=123456789101112131415 and a[15] = 2 .
If someone could tell me what's the problem

for(int j=temp.size();j>0;j--)
{
a.push_back(temp[j]);
}
Here the values of j include temp.size and exclude 0. Since vectors (like basically everything else with integer indices) are 0-indexed, this will access a out of bounds on the first iteration (i.e. when you access temp[temp.size()]).

You have the line g = s; when I think you want g = i;. As written, for s = 5, this will be your vector a: 5 5 5 5 5 Which is not at all what you want.
[Edit] Your handling of numbers > 10 is also off. For example, what happens in your code currently for the number 12? Well, temp will be 1 0 instead of 1 2, and then this will be pushed into a as 0 1, which is again not what you want.
To fix this, think about what k is supposed to do.

Corrected code:
int i, s, g;
vector<int> a;
cin >> s;
for(i=1;i<=s;i++)
{
g = i; //Why was it s?
if(g<10) a.push_back(g);
else {
vector<int> temp;
while(g > 0)
{
int k = g % 10;
g = g / 10;
temp.push_back(k); //You need to push the remainder
}
for(int j=temp.size()-1;j>=0;j--) //Out of bounds error
{
a.push_back(temp[j]);
}
}
}
cout << a[s-1] << endl;
return 0;
And a looks like this when s = 15 - is this what you were looking for?
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 9
a[9] = 1
a[10] = 0
a[11] = 1
a[12] = 1
a[13] = 1
a[14] = 2
a[15] = 1
a[16] = 3
a[17] = 1
a[18] = 4
a[19] = 1
a[20] = 5

I think there's a few problems here.
First, as MBennett said above, you should have done g = i; not g = s; to begin with.
Second, I think your inner loop also has an error, where you should be pushing back k not g as you are now.
Third, you should be doing push_front() not push_back() as you are now. Think of it this way, if you only had that loop, and had the number 162, if you push BACK (not front) every time, then it pushes 2, 6, 1, and so the sequence will have that, and not 1, 6, 2, in the order you want. Your copy after that seems OK, though there's more efficient ways of doing it.
I think that's it. Make those changes and it should function, though I haven't compiled it myself, I'm just solving in my head.

Related

How can I reduce the time complexity of an algorithm in c++?

The following code takes in an integer t and then takes in 3 more integers t times and returns the maximum number of times you can subtract 1 from two different integers at the same time, whereas the program stops when there is only 1 integer above 0 remaining. I have solved the problem, but I want to reduce the time complexity of the code and I don't know how.
#include <bits/stdc++.h>
using namespace std;
int main() {
long long t, r, g, b, arr[1000], count = 0;
bool isMax=true;
cin >> t;
for (long long i = 0; i < t; i++) {
cin >> r >> g >> b;
arr[0] = r;
arr[1] = g;
arr[2] = b;
for (long long j = 0; j < 3; j++) {
for (long long k = 0; k < 2; k++) {
if (arr[k] > arr[k + 1]) {
long long a = arr[k];
long long b = arr[k + 1];
arr[k] = b;
arr[k + 1] = a;
}
}
}
count = 0;
if (arr[2] == 1) {
cout << 1 << endl;
} else if (arr[0] + arr[1] <= arr[2]) {
cout << arr[0] + arr[1] << endl;
} else {
while (arr[0] > 0) {
while (isMax && arr[0] > 0) {
arr[2]--;
arr[0]--;
count++;
if (arr[2] < arr[1]) {
isMax = false;
}
}
while (!isMax && arr[0] > 0) {
arr[1]--;
arr[0]--;
count++;
if (arr[1] < arr[2]) {
isMax = true;
}
}
}
while (arr[2] > 0 && arr[1] > 0) {
arr[2]--;
arr[1]--;
count++;
}
cout << count << endl;
}
}
}
How can I get the same output without using all these loops that increase the time complexity?
Edit: I don't want my code re-written for me, this is homework and all I want are tips and help so I can reduce the time complexity, which I don't know how to do.
Edit 2: In my algorithm, I sort the 3 numbers in ascending order, then I use a while loop to check if the smallest number (s/arr[0]) is > 0. After that, I use two more while loops to alternate between the largest and medium-size numbers (l/arr[2] and m/arr[1] respectively) and decrement from both variables s and l or m (alternating). When s becomes 0, that will mean I can just decrement l and m till one of them equals 0, and then I print the count variable (I increment count every time I decrement two of the variables).
Im not sure if i understood the problem correctly. But if i did you could optimize the algorithem the following way:
int count = 0;
int a = 20, b = 10, c = 21;
sort(a, b, c); // Function that sorts the numbers, so that a is the smallest and c is the largest
count += a; // count = 10
c -= a; // a = 10, b = 20, c = 11
if(c < b) {
float diff = b - c; // diff = 9
float distribute = diff / 2; // distribute = 4.5
count += b - ceil(distribute); // count = 25
}
else count += b;
You would have to this t times and then sum the count variables, resulting in a complexity of t.
Assuming your code is correct, you can examine exactly what your loops are doing, and look at them more mathematically.
if ( arr[2] == 1 ) {
cout << 1 << endl;
} else if ( arr[0] + arr[1] <= arr[2] ) {
cout << arr[0] + arr[1] << endl;
} else {
while ( arr[0] > 0 ) {
if ( arr[2] > arr[1] ) {
long long min = std::min( std::min( arr[0], arr[2] ), arr[2] - arr[1] + 1 );
arr[0] -= min;
arr[2] -= min;
count += min;
} else {
long long min = std::min( std::min( arr[0], arr[1] ), arr[1] - arr[2] + 1 );
arr[0] -= min;
arr[1] -= min;
count += min;
}
}
count += std::min( arr[2], arr[1] );
cout << count << endl;
}
Assuming your program was correct,t his produces the same results for all inputs I tried.
I'm not sure I understood the problem correctly but if you want to know the maximum number of times you can subtract 1 until hitting zero from two elements in a three element set, I believe the answer should be the same as finding the median element of the set. For example, if I have the set
10 20 30
The maximum amount of times I can subtract 1 is 20, if I always chose to subtract from the subset {20, 30}, while the minimum would be 10, if I always choose to subtract from the subset {10, 20}.
Hope this helps! (Assuming I didn't totally misunderstand the question ^_^ ")
Edit:
After the clarifying comment, I believe all you need to do is find the minimum between the sum of the non-maximum elements and the maximum element. Consider the following examples:
If you are given the set {80, 10, 210} for example, the answer to your problem is 90, because we can subtract 10 from the subset {80, 10}, leaving us with {70, 0, 210} where we can further subtract 70 from the subset {70, 210}, leaving us with {0,0,140}, where we can perform no more operations. We have performed 80+10 = 90 subtractions by 1 In this case, max = 210 and min+med = 90
On the other hand, the consider the set {2,2,2}. We can subtract 2 from the subset {2,2}, leaving us with {0,0,2}, where we can perform no more operations. In this case, we have performed 2 subtractions by 1 Max = 2 and min+med = 4
Last example: consider the set {2,3,5}. We can subtract 2 from the subset {2,3}, leaving us with {0,1,5}, where we can the subtract 1 from the subset {1,5}, resulting in {0,0,4}, where we can perform no more operations. In this case, we have performed 2+3=5 subtractions by 1 Max = 5 and min+med = 5
If you continue performing examples in this vein, you should be able to convince yourself that the solution is always going to be min(max, min+median).

How do I optimise TapeEquilibrium solution for large arrays and make it pass all test cases C++

I'm working through codility challanges via C++.
The TapeEquilibrium challange is outlined as follows.
A non-empty array A consisting of N integers is given. Array A represents numbers on a tape.
Any integer P, such that 0 < P < N, splits this tape into two
non-empty parts: A[0], A[1], ..., A[P − 1] and A[P], A[P + 1], ..., A[N − 1].
The difference between the two parts is the value of:
|(A[0] + A[1] + ... + A[P − 1]) − (A[P] + A[P + 1] + ... + A[N − 1])|
In other words, it is the absolute difference between the sum of the
first part and the sum of the second part.
For example, consider array A such that:
A[0] = 3 A[1] = 1 A[2] = 2 A[3] = 4 A[4] = 3
We can split this tape in four places:
P = 1, difference = |3 − 10| = 7 P = 2, difference = |4 − 9| = 5
P = 3, difference = |6 − 7| = 1 P = 4, difference = |10 − 3| = 7
Write a function:
int solution(vector<int> &A);
that, given a non-empty array A of N integers, returns the minimal
difference that can be achieved.
For example, given:
A[0] = 3 A[1] = 1 A[2] = 2 A[3] = 4 A[4] = 3
the function should return 1, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [2..100,000]; each element of array A is an integer within the range [−1,000..1,000].
My C++ solution is as follows:
#include <iostream>
#include <limits>
#include <numeric>
#include <cmath>
// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;
int solution(vector<int> &A) {
// write your code in C++14 (g++ 6.2.0)
if(A.size()==2)
return std::abs(A[0] -A[1]);
vector<int> head;
vector<int> tail;
int minDiff = std::numeric_limits<int>::max();
for(auto itr = A.begin(); itr != A.end(); itr++)
{
head.push_back(*itr);
tail = vector<int>(itr+1, A.end());
int headSum = std::accumulate(head.begin(), head.end(), 0);
int tailSum = std::accumulate(tail.begin(), tail.end(), 0);
minDiff = std::min(std::abs(headSum-tailSum), minDiff);
}
return minDiff;
}
The test cases for this solution:
It's clear that this solution fails when it approaches large sequences. However, given that his solution is O(n); why does it struggle with large vectors and what can I do to optimise this solution?
Also, I have no clue what the "small elements" test cases are testing as the problem description does not mention floats or doubles.
Looks like my previous case wasn't O(n) at all. I've implemented a solution based on this post's solution presented by user IVlad.
The code looks like this:
// you can use includes, for example:
// #include <algorithm>
#include <cmath>
#include <numeric>
#include <limits>
// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;
int solution(vector<int> &A) {
// write your code in C++14 (g++ 6.2.0)
auto B = A;
int difference = std::numeric_limits<int>::max();
if(A.size() == 2)
return std::abs(A[0]-A[1]);
for(uint i = 1; i < A.size(); i++)
B[i] = B[i-1]+A[i];
for(uint i = 0; i < A.size()-1; i++)
{
int headSum = B[i];
int tailSum = B[A.size()-1]-B[i];
difference = std::min(std::abs(headSum-tailSum), difference);
}
return difference;
}
The codility test cases for this algorithm.
This one is also 100% 0(N)
int solution(vector<int> &A) {
// write your code in C++14 (g++ 6.2.0)
int totalSum = 0;
int firstSum = A[0];
for(unsigned int i=1;i<A.size();i++) totalSum += A[i];
int min = abs(firstSum-totalSum);
for(unsigned int i=1;i<A.size()-1;i++){
firstSum+=A[i];
totalSum-=A[i];
if(abs(firstSum-totalSum)<min)
min = abs(firstSum-totalSum);
}
return min;
}

Any ways to make this shorter?

The output is supposed to be in this fashion
I
IN
IND
INDI
INDIA
INDIA
INDI
IND
IN
I
I was wondering if there is anyway to make my program shorter.
Maybe use 2 while loops or 2 for loops instead of 4.
#include<iostream>
#include<conio.h>
using namespace std;
void main()
{
char a[]={'I','N','D','I','A'};
int r,c;
for(r=1;r<=5;r++)
{
for(c=0;c<r;c++)
cout<<a[c]<<" ";
cout<<endl;
}
for(r=5;r>=0;r--)
{
for(c=0;c<r;c++)
cout<<a[c]<<" ";
cout<<endl;
}
_getch();
}
This is nice and short, if you have C++11:
#include <stdio.h>
#include <initializer_list>
int main() {
for (int i : {1,3,5,7,9,9,7,5,3,1})
printf ("%.*s\n", i, "I N D I A") ;
}
I put it on ideone at this link.
The "cheating" ;-) but very short solution is
#include <cstdio>
int main() {
puts("I\nIN\nIND\nINDI\nINDIA\nINDIA\nINDI\nIND\nIN\nI\n");
}
Yet another solution based on TonyK's beautiful idea (works in C and C++):
#include <stdio.h>
int main() {
for (int i = 1; i < 11; ++i)
printf("%.*s\n", i < 6 ? i : 11 - i, "INDIA") ;
}
Update: (After TonyK's comment):
If you want spaces, then replace the printf above with this
printf("%.*s\n", 2*(i < 6 ? i : 11 - i), "I N D I A ");
Update: A solution with no loop:
#include <stdio.h>
int main(int i, char**) {
return printf("%.*s\n", i < 6 ? i : 11 - i, "INDIA") - 1 && main(i + 1, 0);
}
Detailed explanations for the benefit of beginners follow.
The most important point is that this is an "academic" exercise. The code is obscure and one should refrain from writing serious code like this.
The standard doesn't fix a particular signature for the function main. It only says that it must return an int and the compiler must accept two particular forms:
int main();
int main(int argc, char** argv);
I'm using the second one. The more popular form int main(int argc, char* argv[]) is equivalent to (2). Indeed, in general, an array of T used as a function argument is implicitly converted to pointer to T. In this example, char* argv[] is an array of pointer to char which becomes a pointer to pointer to char. The above program is not using the second parameter though (it's either ignored or given a NULL, i.e. 0 value).
Instead of doing a loop, the program calls main recursivelly. Actually, this is illegal but the major compilers turn a blind eye to it (at most GCC gives a warning if you ask it to be pedantic with option -Wpedantic). When the program is called from the command line with no arguments the operating system calls main passing 1 (which is 1 + the number of arguments) and a pointer to pointer to char which, as said, is ignored by this program. Hence, i = 1 at the first call.
Subsequently, main potentially calls itself incrementing i each time. In summary, main is sequentially called with i being 1, 2, 3, 4, ...
It's easy to see that for this sequence of values for i, the expression i < 6 ? i : 11 - i evaluates to 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 0, ... (This can also be expressed by 5.5 - abs(5.5 - i) as per Drew Dorman's solution but using the ternary operator avoids the need to #include <cmath> which saves a line ;-) These numbers are the quantity of characters of "INDIA" that should be displayed at each time.
The call printf("%.s\n", j, "INDIA"), where j = i < 6 ? i : 11 - i, displays the first j characters of "INDIA" followed by a new line and returns the number of characters effectivelly printed (including the new line), i.e. j + 1. Taking away 1 yields j.
We recall now an important point of the semantics of a && b, for integers a and b. If a == 0, then b is not evaluated. Otherwise, b is evaluated. For us, a = printf("%.*s\n", j, "INDIA") - 1 (i.e. a = j) and b = main(i + 1, 0).
Now, let's put these pieces together.
1. Initially, i = 1 and j = 1. The call to printf outputs "I\n" and returns 2. Taking away 1, gives a = 1 != 0. Therefore, b = main(2, 0) is evaluated (that is, main(2, 0) is called).
2. Well, for this second call to main, we have i = 2, j = 2, printf displays "IN\n", a = 2 != 0 and b = main(3, 0) is evaluated.
Repeating this argument, at each call to main we have:
3. i = 3, j = 3, "IND\n" is printed, a = 3 != 0 and main(4, 0) is called.
4. i = 4, j = 4, "INDI\n" is printed, a = 4 != 0 and main(5, 0) is called.
5. i = 5, j = 5, "INDIA\n" is printed, a = 5 != 0 and main(6, 0) is called.
6. i = 6, j = 5, "INDIA\n" is printed, a = 5 != 0 and main(7, 0) is called.
7. i = 7, j = 4, "INDI\n" is printed, a = 4 != 0 and main(8, 0) is called.
...
10. i = 10, j = 1, "I\n" is printed, a = 1 != 0 and main(11, 0) is called.
11. i = 11, j = 0, "\n" is printed, a = 0. Now main(12, 0) is not exectued and the main returns
Notice that main in step 1 calls main in step 2, which calls main in step 3, ... which calls main in step 11. Therefore, main in step 11 returns to main in step 10, which returns to main in step 9, ..., which returns to main in step 1. Finally, main in step 1 returns to the operating system.
If you are interested in even more obfuscated code, see present and past winners of the IOCCC. Enjoy!
Shorter.
#include <iostream>
#include <cmath>
int main()
{
char a[]={'I','N','D','I','A'};
for(int r=1;r<=10;r++)
{
int c = 5.5 - std::abs(5.5 - r);
std::cout << std::string(a, 0, c) << std::endl;
}
}
You could use substr.
Additionally, if you want to add spaces between the characters (as it's in your code right now) you could do that once for the whole word and then work on that modified string:
input = "INDIA";
modifiedInput = ...; // Figure out a way to get "I N D I A " here
for (int i = 1; ...)
cout << substr(modifiedInput, 0, 2 * i) << endl;
...
smth like this:
Anyway, 2 loops is hard thing)
int i=1;
bool ind=0;
for(r=0;r<10;r++)
{
if (ind == 0){
for(c=0;c<i;c++)
cout<<a[c]<<" ";
i++; }
if (ind == 1){
for(c=0;c<i;c++) cout<<a[c]<<" ";
i--;
}
if (i % 5 == 0) ind=1;
cout<<endl;
}
Here is an example using two loops:
#include<iostream>
using namespace std;
int main()
{
char a[]={'I','N','D','I','A'};
int arr_length=5;
bool two_times=false;//if you want to output INDIA twice
for(int i=2*arr_length-1; i>=1; i--)
{
for(int j=0; j<arr_length-abs(arr_length-i); j++)
{
cout << a[j];
}
if(i==arr_length && !two_times){ two_times=true; i++;}//if you want to output INDIA twice
cout << endl;
}
return 0;
}
Output:
I
IN
IND
INDI
INDIA
INDIA
INDI
IND
IN
I
You can do like this:
void main()
{
char a[]={'I','N','D','I','A'};
int r,c;
int x = 0; // initially x is 0
int l = 5;
for(r=1;r<= 11 ;r++) //loop runs for 5*2 + 1 times
{
if(r>=6){
x = l - r % 6; //set x to remaining length
l--;
}
for(c=0;c< (r % 6) + x; c++) // add x
cout<<a[c]<<" ";
cout<<endl;
}
}
and you can find it working here.
Another solution based on TonyK's answer. You can enter your desired string.
#include <stdio.h>
#include <string.h>
int main() {
char s[100];
gets(s);
for (int i = 0; i < strlen(s) * 2; i++)
printf ("%.*s\n", i < strlen(s) ? i + 1: 2 * strlen(s) - i, s);
}
http://ideone.com/Zsg5Lu

Creating all possible k combinations of n items in C++

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;
}

Retrieval of items from a knapsack using dynamic programming

I'm new to dynamic programming and have tried my first DP problem. The problem statement is
Given a knapsack of size C, and n items of sizes s[] with values v[], maximize the capacity of the items which can be put in the knapsack. An item may be repeated any number of times. (Duplicate items are allowed).
Although I was able to formulate the recurrence relation and create the DP table, and eventually get the maximum value that can be put in the knapsack, I am not able to device a method to retrieve which values have to be selected to get the required sum.
Here is my solution:
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int s[] = { 1, 3, 4, 5, 2, 7, 8 , 10};
int v[] = { 34, 45, 23, 78, 33, 5, 7 , 1};
int n = ( (sizeof(s)) / (sizeof(s[0])) );
vector<int> backtrack;
int C = 15;
int pos;
int m[20];
m[0] = 0;
int mx = 0;
for ( int j = 1; j <= C; j++) {
mx = 0;
m[j] = m[j-1];
pos = j-1;
for ( int i = 0; i < n; i++) {
mx = m[i-s[i]] + v[i];
if ( mx > m[i] ) {
m[i] = mx;
pos = i - s[j];
}
}
backtrack.push_back(pos);
}
cout << m[C] << endl<<endl;
for ( int i = 0; i < backtrack.size(); i++) {
cout << s[backtrack[i]] <<endl;
}
return 0;
}
In my solution, I've attempted to store the positions of the maximum value item selcted in a vector, and eventually print them. However this does not seem to give me the correct solution.
Running the program produces:
79
2
3
0
5
2
7
8
10
34
45
23
78
33
5
7
It is obvious from the output that the numbers in the output cant be the sizes of the items selected as there there no item of size 0 as shown in the output.
I hope that you will help me find the error in my logic or implementation. Thanks.
You are following the greedy approach. It's pretty clever , but it is heuristic. I will not give you the correct code, as it might be a homework, but the recursive function knapsack would look like this:
knapsack(C): maximum profit achivable using a knapsack of Capacity C
knapsack(C) = max { knapsack(C-w[i]) + v[i] } for all w[i] <= C
knapsack(0) = 0
In code:
dp(0) = 0;
for i = 1 to C
dp(i) = -INF;
for k = i-1 downto 0
if w[k] < i then
dp(i) = max{dp(i-w[k]) + v[k], dp(i)};
print dp(Capacity);