Tutorial for Paying Up |
Hello,
The problem "Paying Up" was one of the easy ones in the March 2009 contest on Codechef. It is considered an easy problem, because it has a couple of approaches that work. The problem statement boils down to finding a subset of banknotes such that their sum is exactly equal to a certain value. Now, this problem is somewhat similar to the knapsack problem which asks for ways to fill up a knapsack of a certain size optimally with the given blocks. There is a solution based on dynamic programming for this problem, but we will be taking up a solution which makes good use of the way integers are represented in binary to solve this problem.
Now, the limit on the number of banknotes is 'n'. Let us see how many subsets exist for these banknotes. For finding the number of subsets, we see that for every banknote, we have two choices, either to choose it in our calculation for the sum of notes or to ignore it in calculating the sum. Thus, we have 2 options per banknote and 'n' banknotes. So, the total number of subsets thus becomes 2^n where ^ represents the power operation. The number of subsets are small enough for us to bruteforce through them and the program to run in time.
An interesting way to generate all subsets of 'n' objects when 'n' is considerably small (n <= 20) is to use the properties of how unsigned integers are stored. Consider the number 2^n. This number is represented in binary form as '10000...0', that is, 1 followed by n 0s. Also, any number containing a 1 at the same position will surely be greater than 2^n. Thus, all numbers below 2^n do not have a 1 in a position greater than or equal to 'n' starting from the LSB. By induction, we can do the same for values of n = n-1 and n-2 and so on. Thus, we can see that any number between 2^(n-1) and 2^n will have a 1 in the position n-1. Extending this logic, we can say that if we consider the numbers from 1 to 2^n, we would be considering all possible ways in which we can choose some objects from 'n' objects.
For example, consider n = 3, so 2^n = 8. Let us list 'i' and its binary representation
i Binary representation using 'n' bits
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111
As you can see, if we consider that 1 means that we have selected object at that position and 0 means that we have not selected the object at that position, we can get all possible subsets of 'n' objects by looping over numbers from 1 to 2^n.
For calculating the sum of the subset represented by 'i', we loop from 0 to 'n' and we check whether the corresponding bit is set in the value for 'i' or not. If it is, we include that object in calculating our sum else we don't. In this way, we can get the sum for all possible subsets of the 'n' objects.
This is exactly what we need for this problem. After taking in the number of objects, we loop 'i' from 1 to 2^n incrementing the value of 'i' by 1 at every stage to give us a new subset. Then for a particular value of 'i', we loop 'j' from 0 to n and check if the bit at that particular value is set or not. Languages like C / C++ provide bit-wise operators for leftshift and rightshift. For checking if the bit is set at position 'j'(starting from 0) we can just check if the value of (i & (1<<j)) is 0. If it is 0, then the bit is not set, while if it is greater than 0, then the bit is set. Alternatively, we can also loop from 0 to n and at each stage check whether 'i' modulo 2 is equal to 1 or not. If it is 1, then the bit at that position is set, else it's not. Then we divide 'i' by 2 and proceed. At the end of the 'n' iterations, 'i' will equal 0. The problem with this appraoch is that the modulo operations take much more time compared to the bitwise operations. Thus, now that we know how to check if the bit is set, we initialize a value 'sum' equal to 0 at the start of the 'n' iterations for a value of 'i' and if the bit at position 'j' is set, we add the corresponding banknote value to 'sum' else we don't. At the end of these iterations, we check if the value of 'sum' equals the required value. If it does, then we have found a subset with the required sum and so we print a "Yes" and exit. Else, if at the end of 2^n iterations of 'i' we don't have a subset with the required sum, then we print a "No" and exit.
The program should look something like this :
[code]
Start
Take in the value of 'n' and the required value of sum 'm'
Take in all the values for the banknotes in array 'd[]'
For i = 1 and i < (2^n)
sum = 0
For j = 0 and j < n
if jth bit of i is set
sum = sum + d[j]
if sum equals m
print Yes and return
Print No and return
[/code]
Comments


can smone fnd error in my
can smone fnd error in my code i dnt why it's giving wrong answer...............#include<stdio.h>
int main(void) {
int t,n,m;
int i,j,s,a[20];
//clrscr();
scanf("%d",&t);
while(t--) {
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=1;i<(1<<n);i++) {
s=0;
for(j=0;j<n;j++)
if(i&(1<<j)>0)
s=s+a[j];
if(s==m) {
printf("YESn");
goto end;
}
}
printf("NOn");
end : continue;
}
return 0;
}
Your problem fails the sample
Your problem fails the sample input. And in fact, every single case. Read the problem statement again.
very nice tutorial . . .
very nice tutorial . . . .learned some new efficient ways to play with number of the form of power of 2 . . .thanks a lot CodeChef ! ! ! :)
the application of binary
the application of binary representation is applied.its nice to see
can anyone plz check the
can anyone plz check the error in it..it is giving runtime error...
#include<iostream>
using namespace std;
void ins(int*,int);
int main()
{
int t,n,m,c=0,i,j;
int *b=new int[t];
for(i=0;i<t;i++)
b[i]=0;
cin>>t;
while(t>0)
{
cin>>n>>m;
int *a=new int[n];
for(i=0;i<n;i++)
{
cin>>a[i];
}
ins(a,n);
int sum=0;
for(i=0;i<n;i++)
{
if(b[c]!=1)
{
sum=a[i];
for(j=i+1;j<n;j++)
{
if(sum+a[j]<m)
{
sum=sum+a[j];
}
else if(sum+a[j]>m)
continue;
else if(sum+a[j]==m)
{
b[c]=1;
break;
}
}
}
}
c++;
t--;
}
for(i=0;i<c;i++)
{
if(b[i]==0)
cout<<"n"<<"NO";
else
cout<<"n"<<"YES";
}
}
void ins(int a[] ,int n)
{
int i,j,key1;
for(j=1;j<n;j++)
{
key1=a[j];
i=j-1;
while(key1>a[i]&&i>=0)
{
a[i+1]=a[i];
i--;
}
i++;
a[i]=key1;
}
}
#include<iostream>#include<cm
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int i,n,m,sum,temp,t,me;
cout<<"Enter number of test cases:";
cin>>t;
for(int p=0;p<t;p++)
{
int flag=0;
cout<<"nEnter the number of notes in wallet:";
cin>>n;
cout<<"nEnter the amount you want:";
cin>>m;
cout<<"nEnter the values of the "<<n<<" notes you have:n";
int *note;
note = new int [n];
int iarr[n];
for (i=0;i<n;i++)
{
cin>>note[i];
iarr[i]=0;
}
for (i=0;i<(1<<n);i++)
{
me=i;
for(temp=0;temp<n;temp++)
{
iarr[temp]=me%2;
me=me/2;
}
sum=0;
for(int j=0;j<n;j++)
{
if(iarr[j]==1)
sum=sum+note[j];
}
if (sum==m)
{
cout<<"Yesn";
flag=1;
break;
}
}
if(flag==0)
cout<<"No!n";
}
return 0;
}
some one expalin the problem with the code :(
Please don't post code. Read
Please don't post code. Read the FAQ.
great tutorial,, THANKS A
great tutorial,, THANKS A MILLION!!
nice tutorial this approach
nice tutorial this approach is way better than mine
Excellent technique of
Excellent technique of generating subsets!
what will be complexity of
what will be complexity of this algorithm in big O notation??
what will be complexity of d
what will be complexity of d above algorithm in big O notation??
I always had a problem with
I always had a problem with permutations.Thanks for this technique.
This will help me a lot!
"any number containing a 1 at
"any number containing a 1 at the same position will surely be greater than 2^n"
ehat does that mean??
whats wrong with this
whats wrong with this example?can anyone explain?
#include <iostream>
using namespace std;
int main()
{
int a[2] = {1,2};
int sum = 0;
for(int i=1;i<4;i++)
{
sum = 0;
for(int j=0;j<2;j++)
{
if(i&(1<<j)!=0)
{
sum += a[j];
}
}
cout << sum <<" ";
}
}
@ashiqul mostofa : supoose
@ashiqul mostofa : supoose any number < 2^n ( take any n) . let 5 be a number and n=2. its binary reperesnetation is 101 . here 1 is at 2nd position . it is olwayz be greater than a number 2^2 i.e 4 .
hello i m not getting y we
hello i m not getting y we add d[i] to sum only when i & (1<<j) is > 0 .
i hav read this tutorial 2-3 times...but i m not able to get that point... wud nay1 please explore more about it...:)
The Complexity of the above
The Complexity of the above solution is still high we need better solution to it.
worse case O(n2^n)
best case O(2^n)
note* Not sure if i am correct. try to find notaion by usrself, and post the correction if any.
nice tutorial :)
nice tutorial :)
Umm, i really think my logic
Umm, i really think my logic is correct. Can somebody please check my solution ?
http://www.codechef.com/viewsolution/491186
Help will be really appreciated
Thanks :D
awesome solution!!!!!
awesome solution!!!!!
BRAVO!!! OUTSTANDING, i cant
BRAVO!!! OUTSTANDING, i cant express but i am so imressed with this technique, i spent about 3 days on this question for finding the solustion on my own, but this technique is really awsome.
really awsome tutorial, a lot
really awsome tutorial,
a lot of thanks.
from sys import * def
_/\_ Bow Bow. Kudos!! Great
awesome!!
amazing tutorials :)
this IS
#include #include main() { i
what is the problem in above
#include #include main() {
Why the value of sum is not
#include #include #include in
do backtraking in this