// A Dynamic programming based C++ program to find number of
// non-negative solutions for a given linear equation
#include<bits/stdc++.h>
using namespace std;
// Returns counr of solutions for given rhs and coefficients
// coeff[0..n-1]
int countSol(int coeff[], int n, int rhs)
{
// Create and initialize a table to store results of
// subproblems
int dp[rhs+1];
memset(dp, 0, sizeof(dp));
dp[0] = 1;
// Fill table in bottom up manner
for (int i=0; i<n; i++)
for (int j=coeff[i]; j<=rhs; j++)
dp[j] += dp[j-coeff[i]];
return dp[rhs];
}
// Driver program
int main()
{
int coeff[] = {2, 2, 5};
int rhs = 4;
int n = sizeof(coeff)/sizeof(coeff[0]);
cout << countSol(coeff, n, rhs);
return 0;
}
I am new to competitive programming, I just stumbled upon this code. I would like to know the intuition behind this particular snippet, like how does the second for loop help. Thank you.
// Fill table in bottom up manner
for (int i=0; i<n; i++)
for (int j=coeff[i]; j<=rhs; j++)
dp[j] += dp[j-coeff[i]];
This is using a bottom up approach, and
Suppose if j= 3 and j-coeff[i] = 2
so how does d[3] = d[3] + d[2] give the solution? How can a simple addition of a previous result and a current result give the total solution of linear variables?
Imagine that you have unlimited number of coins with value 2,3,5 (your coeff[]) and you want to know number of solutions to make some sum form give coin set.
At the first loop run you fill table with coins 2. Table will be filled
idx 0 1 2 3 4 5 6
num 1 0 1 0 1 0 1
because there is the only way to get even sum with such coins.
At the second loop run you fill table with coins 3 - now you'll have sums that might be composed from coins 2 and 3
idx 0 1 2 3 4 5 6
num 1 0 1 1 1 1 2
Note that cell 5 filled with 2+3 - similar to your question situation, and cell 6 now contains 2 variants: 2+2+2 and 3+3
Related
I was solving one problem and it stated that we need to find the sum of all minimum number that needs to be added to the elements in the array so that the bitwise AND is greater than 0.
For eg: Given array is [4, 4, 3, 2]
then the output should be 3
(adding one to 1st 2nd and 4th element).
My approach : first I decided to find the position of the right most set in all elements and check for the overall minimum number to be added so that the and is greater than zero. But this is not working.Can anyone help in finding an alternative algo?
Let's solve a bit different problem first:
What minimum min number should be add to value to ensure 1 in kth position (zero based)?
We have two cases here:
if value has 1 at k position we add 0 (do nothing);
if value has 0 at k position we can add
min = 100...000000000 - (value & 11.....11111)
<- k zeroes -> <- k ones ->
Code (C#)
private static long AddToEnsureOne(long value, int position) {
if ((value & (1L << position)) != 0)
return 0;
long shift = 1L << (position);
return shift - (value & (shift - 1));
}
Demo: if we have 3 and we want 1 at 2nd position
0b011
^
we want 1 here
we should add
0b100 - (0b011 & 0b11) == 4 - 3 == 1
let's add: 3 + 1 == 4 == 0b100 which has 1 at 2nd position
Now we can scan all 32 positions (if integer is good old 32 bit integer int); C# code:
private static long MinToAdd(IEnumerable<int> items) {
long best = 0;
for (int i = 0; i < 32; ++i) {
long sum = 0;
foreach (int item in items)
sum += AddToEnsureOne(unchecked((uint)item), i); // uint - get rid of sign
if (i == 0 || sum < best)
best = sum;
}
return best;
}
One can improve the solution looping not for 32 positions but for the leftmost 1 of the maximum item. Here we have 4 as the maximum, which is 0b100, the leftmost 1 is in the 2 position; thus for (int i = 0; i <= 2; ++i) will be enough in the context
Simple test:
Console.Write(MinToAdd(new int[] { 4, 4, 3, 2}));
Outcome:
3
So I want to know how to count all the solutions for a knapsack problem. Namely I'm interested in finding the number of possible subsets from a set of numbers that have the maximum size of K.
e.g we have a set of items of size {3, 2, 5, 6, 7} and the max size is K = 13. So the solutions are {5, 6, 2} and {6, 7}. On the other hand there are two solutions; I want my dynamic programming algorithm to report there are two possible solutions.
This can be done with dynamic programming. The basic strategy is to build a memorization table, d[i][j], which stores the number of combinations using the first j numbers that sum to i. Note that j = 0 represents an empty set of numbers. Here is a sample implementation:
int countCombinations(int[] numbers, int target) {
// d[i][j] = n means there are n combinations of the first j numbers summing to i.
int[][] d = new int[target + 1][numbers.length + 1];
// There is always 1 combination summing to 0, namely the empty set.
for (int j = 0; j <= numbers.length; ++j) {
d[0][j] = 1;
}
// For each total i, calculate the effect of using or omitting each number j.
for (int i = 1; i <= target; ++i) {
for (int j = 1; j <= numbers.length; ++j) {
// "First j numbers" is 1-indexed, our array is 0-indexed.
int number = numbers[j - 1];
// Initialize value to 0.
d[i][j] = 0;
// How many combinations were there before considering the jth number?
d[i][j] += d[i][j - 1];
// How many things summed to i - number?
if (i - number >= 0) {
d[i][j] += d[i - number][j - 1];
}
}
}
// Return the entry in the table storing all the number combos summing to target.
return d[target][numbers.length - 1];
}
Just to add some Google keywords: this problem is also known as summing n coins without repeats to a target sum.
There is a dynamic knapsack solution for this task.In dp array dp[i] stores the number of subsets which their sum is "i". In this case your answer is dp[K].( Sorry for indentation problems I could not figure out how to make it right :( )
dp[0] = 1 ;
for( int i=0; i<N ; i++ )
for( int j=K-a[i] ; j>=0 ; j-- )
dp[j+a[i]] += dp[j]
I don't think Max's algorithm works for the case: [0,0,1] with target of 1. The answer is 4 but his algorithm will output 1. His algorithm only works for positive integers, because it assumes that a sum of 0 can only be achieved with empty set. However, it can also be achieved if 0 exists in the array. The more robust way of tackling this problem (and also more space efficient) is using a 1D dp array. The pseudo-code is the following:
int[] dp = new int[target+1];
for (int num : nums) {
for (int s = target; s >= 0; s--) {
if (s >= num) { // can include num
dp[s] += dp[s-num];
} else { // cannot include num (can be omitted, here for better explanation)
dp[s] += 0;
}
}
}
return dp[target+1];
The reason I backtrack from target to 0 in the inner for loop is to avoid duplication. Think about the example [2,2,2] with target sum of 4. If you iterate from index 0, then you would double count a 2 when you are at dp[4] (should be [1 0 1 0 0] instead of [1 0 1 0 1] after one iteration in inner loop).
Hope this helps.
I recently encountered this problem in an interview
There are n stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 stair or 2 stairs at a time.
Print all possible ways person can reach the top.
For example, n=4 Output:
1 2 3 4
1 2 4
1 3 4
2 3 4
2 4
But I couldn't code this properly. How to code up solution for this?
To print the number of ways, you can first understand how to calculate the number of ways, and adjust it so each "count" will print instead of just count:
D(0) = 1
D(-1) = 0
D(i) = D(i-1) + D(i-2)
To adjust it to actual printing, you need to "remember" the choices you have made, and follow the same logic. Pseudo code:
printWays(curr, n, soFar):
if curr > n:
return
soFar.append(curr)
if n == curr:
print soFar
soFar.removeLast()
return
printWays(curr+1,n,soFar)
printWays(curr+2,n,soFar)
soFar.removeLast()
The idea is:
soFar is the current series of steps you did.
curr is the current step you're at.
n is the last stair you need to get to.
At each point, you either climb one stair or two. You check both options.
You can try some recursive solution where you call recursively CanClimb(n-1) and CanClimb(n-2) to visualize the possible ways.
Sample solution in C#:
public static void ClimbWays(int n, int currentIndex, int[] currectClimb)
{
if (n < 0) return;
if (n == 0)
{
for (var i = currentIndex - 1; i >= 0; i--)
{
Console.Write(currectClimb[i] + " ");
}
Console.WriteLine();
return;
}
currectClimb[currentIndex] = n;
ClimbWays(n - 1, currentIndex + 1, currectClimb);
ClimbWays(n - 2, currentIndex + 1, currectClimb);
}
Output for ClimbWays(4, 0, new int[4]);:
1 2 3 4
2 3 4
1 3 4
1 2 4
2 4
If you want to just count them you can use the well known Fibonacci sequence which can be calculated iteratively:
public static int Fibonacci(int n)
{
int a = 0;
int b = 1;
// In N steps compute Fibonacci sequence iteratively.
for (int i = 0; i < n; i++)
{
int temp = a;
a = b;
b = temp + b;
}
return a;
}
I have an algorithm problem. I am trying to find all unique subset of values from a larger set of values.
For example say I have the set {1,3,7,9}. What algorithm can I use to find these subsets of 3?
{1,3,7}
{1,3,9}
{1,7,9}
{3,7,9}
Subsets should not repeat, and order is unimportant, set {1,2,3} is the same as set {3,2,1} for these purposes. Psudocode (or the regular kind) is encouraged.
A brute force approach is obviously possible, but not desired.
For example such a brute force method would be as follows.
for i = 0 to size
for j = i + 1 to size
for k = j + 1 to size
subset[] = {set[i],set[j],set[k]}
Unfortunately this requires an additional loop for each element desired in the subset, which is undesirable if, for example, you want a subset of 8 elements.
Some Java code using recursion.
The basic idea is to try to swap each element with the current position and then recurse on the next position (but we also need startPos here to indicate what the last position that we swapped with was, otherwise we'll get a simple permutation generator). Once we've got enough elements, we print all those and return.
static void subsets(int[] arr, int pos, int depth, int startPos)
{
if (pos == depth)
{
for (int i = 0; i < depth; i++)
System.out.print(arr[i] + " ");
System.out.println();
return;
}
for (int i = startPos; i < arr.length; i++)
{
// optimization - not enough elements left
if (depth - pos + i > arr.length)
return;
// swap pos and i
int temp = arr[pos];
arr[pos] = arr[i];
arr[i] = temp;
subsets(arr, pos+1, depth, i+1);
// swap pos and i back - otherwise things just gets messed up
temp = arr[pos];
arr[pos] = arr[i];
arr[i] = temp;
}
}
public static void main(String[] args)
{
subsets(new int[]{1,3,7,9}, 0, 3, 0);
}
Prints:
1 3 7
1 3 9
1 7 9
3 7 9
A more detailed explanation (through example):
First things first - in the above code, an element is kept in the same position by performing a swap with itself - it doesn't do anything, just makes the code a bit simpler.
Also note that at each step we revert all swaps made.
Say we have input 1 2 3 4 5 and we want to find subsets of size 3.
First we just take the first 3 elements - 1 2 3.
Then we swap the 3 with 4 and 5 respectively,
and the first 3 elements gives us 1 2 4 and 1 2 5.
Note that we've just finished doing all sets containing 1 and 2 together.
Now we want sets of the form 1 3 X, so we swap 2 and 3 and get 1 3 2 4 5. But we already have sets containing 1 and 2 together, so here we want to skip 2. So we swap 2 with 4 and 5 respectively, and the first 3 elements gives us 1 3 4 and 1 3 5.
Now we swap 2 and 4 to get 1 4 3 2 5. But we want to skip 3 and 2, so we start from 5. We swap 3 and 5, and the first 3 elements gives us 1 4 5.
And so on.
Skipping elements here is perhaps the most complex part. Note that whenever we skip elements, it just involves continuing from after the position we swapped with (when we swapped 2 and 4, we continued from after the 4 was). This is correct because there's no way an element can get to the left of the position we're swapping with without having been processed, nor can a processed element get to the right of that position, because we process all the elements from left to right.
Think in terms of the for-loops
It's perhaps the simplest to think of the algorithm in terms of for-loops.
for i = 0 to size
for j = i + 1 to size
for k = j + 1 to size
subset[] = {set[i],set[j],set[k]}
Each recursive step would represent a for-loop.
startPos is 0, i+1 and j+1 respectively.
depth is how many for-loops there are.
pos is which for-loop we're currently at.
Since we never go backwards in a deeper loop, it's safe to use the start of the array as storage for our elements, as long as we revert the changes when we're done with an iteration.
If you are interested only in subsets of size 3, then this can be done using three simple nested for loops.
for ( int i = 0; i < arr.size(); i++ )
for ( int j = i+1; j < arr.size(); j++ )
for ( int k = j+1; k < arr.size(); k++ )
std::cout << "{ " << arr[i] <<"," << arr[j] <<"," << arr[k] <<" }";
For a more general case you will have to use recursion.
void recur( set<int> soFar, set<int> remaining, int subSetSize ) {
if (soFar.size() == subSetSize) {
print soFar;
return;
}
for ( int I = 0; I < remaining.size(); I++ ) {
//take out Ith element from remaining and push it in soFar.
// recur( newSofar, newRemaining, subSetSize);
}
}
I have been trying to formulate an algorithm to solve a problem. In this problem, we have a photo containing some buildings. The photo is divided into n vertical regions (called pieces) and the height of a building in each piece is given.
One building may span several consecutive pieces, but each piece can only contain one visible building, or no buildings at all. We are required to find the minimum number of buildings.
e.g.
given ,
3 ( no of pieces)
1 2 3 ( heights) ans = 3
3
1 2 1 ans = 2
6
1 2 3 1 2 3 ans = 5 ( a figure wud help show the overlap.).
Though I feel like I get it, I am unable to get a solid algorithm for it. Any ideas?
You can find the lowest number from the given array and account for all occurances of this number. This will split the array into multiple subarrays and now you need to recursively solve the problem for each of them.
In the example:
1 2 3 1 2 3 (total = 0)
Smallest number is 1:
x 2 3 x 2 3 (total = 1)
Now you have 2 subarrays.
Solve for the first one - the smallest number is 2:
x 3 (total = 2)
Finally you have a single element: total = 3
Solving the other subarray makes it 5.
Here is some code in C#:
int Solve(int[] ar, int start, int end){
//base for the recursion -> the subarray has single element
if(end-start == 1) return 1;
//base for the recursion -> the subarray is empty
if(end-start < 1) return 0;
//find min
int m = int.MaxValue;
for(int i = start; i < end; i++)
if (ar[i] < m) m = ar[i];
int total = 1;
//find the subarrays and their contribution recursively
int subStart = start;
for(int subEnd = start; subEnd < end; subEnd++){
if(ar[subEnd] == m) {
total += Solve(ar, subStart, subEnd);
subStart = subEnd + 1;
}
}
total += Solve(ar, subStart, ar.Length);
return total;
}