0/1 Knapsack with Minimum Cost - dynamic-programming

The famous 0/1 knapsack problem focuses on getting the maximum cost/value in the given Weight (W).
The code for the above is this ::
n = cost_array / weight_array size
INIT :: fill 0th col and 0th row with value 0
for (int i=1; i<=n; i++) {
for (int j=1; j<=W; j++) {
if (weight[i-1] <= j) {
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - weight[i-1]] + cost[i-1]);
}else {
dp[i][j] = dp[i-1][j];
}
}
}
Ans :: dp[n][W]
NEW Problem :: So, here we are calculating the maximum cost/value. But what if I want to find the minimum cost/value (Its still bounded knapsack only).
I think the problem boils down how I do the INIT step above. As in the loop I think it will remain same with the only difference of Math.max becoming Math.min
I tried the INIT step with Infinity, 0 etc but am not able to build the iterative solution.
How can we possibly do that?

Writing answer as mentioned by #radovix
Convert every weight to negative number and write the same algorithm.

here's an efficient algorithm for your problem written in JS (minimal-cost maximal knapsacking) with time complexity O(nC) and space complexity O(n+C) instead of the obvious solution with space complexity O(nC) with a DP matrix.
Given a knapsack instance (I, p,w, C), the goal of the MCMKP (Minimum-Cost Maximal Knapsack Packing) is to find a maximal knapsack packing S⊂I that minimizes the profit of selected items
const knapSack = (weights, prices, target, ic) => {
if (weights.length !== prices.length) {
return null;
}
let weightSum = [0],
priceSum = [0];
for (let i = 1; i < weights.length; i++) {
weightSum[i] = weights[i - 1] + weightSum[i - 1];
priceSum[i] = prices[i - 1] + priceSum[i - 1];
}
let dp = [0],
opt = Infinity;
for (let i = 1; i <= target; i++) dp[i] = Infinity;
for (let i = weights.length; i >= 1; i--) {
if (i <= ic) {
const cMax = Math.max(0, target - weightSum[i - 1]),
cMin = Math.max(0, target - weightSum[i - 1] - weights[i - 1] + 1);
let tmp = Infinity;
for (let index = cMin; index <= cMax; index++) {
tmp = Math.min(tmp, dp[index] + priceSum[i - 1]);
}
if (tmp < opt) opt = tmp;
}
for (let j = target; j >= weights[i - 1]; j--) {
dp[j] = Math.min(dp[j], dp[j - weights[i - 1]] + prices[i - 1]);
}
}
return opt;
};
knapSack([1, 1, 2, 3, 4],[3, 4, 6, 2, 1],5,4);
In the following code above, we define a critical item, as an item whose weight gives a tight upper bound on the smallest possible item left out of any feasible solution.
the index of the critical item, i.e., the index of the first item that exceeds the capacity, assuming all i ≤ ic
will be taken as well. opt is the optimal solution.
Observe that the items {1, . . . , i − 1} determine the remaining capacity of the knapsack
(which is given as cMax) that has to be filled using items from {i + 1, . . . , n}, whereas cMin is determined by to the fact that the packing has to be maximal and that item i is the smallest one taken out of the solution

Related

calculate maximum sum if same number is picked from continuous segment

calculate maximum sum if same number is picked from continuous segment
[1,2,3,4] => answer 6
if 1 is picked from continuous segment [1,1,1,1] then sum is 4
if 2 is picked from continuous segment [2,3,4] then sum is 6 ,
[6,0,6,5,5,2] => answer 15, continuous segment [6,5,5] ,
5 can be picked from 3 elements.
[1,100,1,1] => answer 100, we can't pick 1 as 1+1+1+1 = 4 <100
I can't think any solution except O(n^2) loop
O(n) complexity. Use a stack. While numbers are increasing push indexes to stack. If the number is equal or lower or the array ends, pop the indexes of equal or larger numbers from the stack and calculate. Continue.
JavaScript code:
function f(arr){
let stack = [0];
let best = arr[0];
function collapse(i, val){
console.log(`Collapsing... i: ${i}; value: ${val}`);
while (stack.length && arr[ stack[stack.length - 1] ] >= val){
let current_index = stack.pop();
let left_index = stack.length ? stack[stack.length - 1] : -1;
console.log(`i: ${i}; popped: ${current_index}; value: ${arr[current_index]}; potential: ${i - left_index - 1} * ${arr[current_index]}`)
best = Math.max(best, (i - left_index - 1) * arr[current_index]);
}
}
console.log('Starting... stack: ' + JSON.stringify(stack));
for (let i=1; i<arr.length; i++){
if (!stack.length || arr[ stack[stack.length - 1] ] < arr[i]){
stack.push(i);
console.log(`Pushing ${i}; stack: ${JSON.stringify(stack)}`);
} else {
collapse(i, arr[i]);
stack.push(i);
console.log(`Pushing ${i}; stack: ${JSON.stringify(stack)}`);
}
}
if (stack.length)
collapse(stack[stack.length - 1] + 1, -Infinity);
return best;
}
//console.log(f([5,5,4]))
//console.log(f([1,2,3,4]))
console.log(f([6,0,6,5,5,2]))
#גלעד ברקן's answer is right and should be accepted. However I decided to implement the stack solution for the sake of interest and to help #xyz sort it out.
let a = [5,5,4,4,6];
console.log(`Answer: ${traverse(a)}`);
function traverse(a) {
let i, max = 0, stack = [0];
for (i = 1; i < a.length; i++) {
if (a[i] >= a[stack[stack.length - 1]]) {
stack.push(i);
} else {
pop(i);
stack.push(i);
}
}
if (stack.length) pop(i, true);
function pop(index, end) {
while (stack.length && (a[stack[stack.length - 1]] >= a[index] || end)) {
let p = stack.pop();
let range = stack.length ? index - stack[stack.length - 1] - 1 : index;
max = Math.max(max, range * a[p]);
}
}
return max;
}

Dynamic Programming, choosing the highest total value

The Data:
A list of integers increasing in order (0,1,2,3,4,5.......)
A list of values that belong to those integers. As an example, 0 = 33, 1 = 45, 2 = 21, ....etc.
And an incrementing variable x which represent a minimum jump value.
x is the value of each jump. For example if x = 2, if 1 is chosen you cannot choose 2.
I need to determine the best way to choose integers, given some (x), that produce the highest total value from the value list.
EXAMPLE:
A = a set of 1 foot intervals (0,1,2,3,4,5,6,7,8,9)
B = the amount of money at each interval (9,5,7,3,2,7,8,10,21,12)
Distance = the minimum distance you can cover
- i.e. if the minimum distance is 3, you must skip 2 feet and leave the money, then you can
pick up the amount at the 3rd interval.
if you pick up at 0, the next one you can pick up is 3, if you choose 3 you can
next pick up 6 (after skipping 4 and 5). BUT, you dont have to pick up 6, you
could pick up 7 if it is worth more. You just can't pick up early.
So, how can I programmatically make the best jumps and end with the most money at the end?
So I am using the below equation for computing the opt value in the dynamic programming:
Here d is distance.
if (i -d) >= 0
opt(i) = max (opt(i-1), B[i] + OPT(i-d));
else
opt(i) = max (opt(i-1), B[i]);
Psuedo-code for computing the OPT value:
int A[] = {integers list}; // This is redundant if the integers are consecutive and are always from 0..n.
int B[] = {values list};
int i = 0;
int d = distance; // minimum distance between two picks.
int numIntegers = sizeof(A)/sizeof(int);
int opt[numIntegers];
opt[0] = B[0]; // For the first one Optimal value is picking itself.
for (i=1; i < numIntegers; i++) {
if ((i-d) < 0) {
opt[i] = max (opt[i-1], B[i]);
} else {
opt[i] = max (opt[i-1], B[i] + opt[i-d]);
}
}
EDIT based on OP's requirement about getting the selected integers from B:
for (i=numIntegres - 1; i >= 0;) {
if ((i == 0) && (opt[i] > 0)) {
printf ("%d ", i);
break;
}
if (opt[i] > opt[i-1]) {
printf ("%d ", i);
i = i -d;
} else {
i = i - 1;
}
}
If A[] does not have consecutive integers from 0 to n.
int A[] = {integers list}; // Here the integers may not be consecutive
int B[] = {values list};
int i = 0, j = 0;
int d = distance; // minimum distance between two picks.
int numAs = sizeof(A)/sizeof(int);
int numIntegers = A[numAs-1]
int opt[numIntegers];
opt[0] = 0;
if (A[0] == 0) {
opt[0] = B[0]; // For the first one Optimal value is picking itself.
j = 1;
}
for (i=1; i < numIntegers && j < numAs; i++, j++) {
if (i < A[j]) {
while (i < A[j]) {
opt[i] = opt[i -1];
i = i + 1:
}
}
if ((i-d) < 0) {
opt[i] = max (opt[i-1], B[j]);
} else {
opt[i] = max (opt[i-1], B[j] + opt[i-d]);
}
}

coin change recurrence solution

Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued coins, how many ways can we make the change? The order of coins doesn’t matter.There is additional restriction though: you can only give change with exactly K coins.
For example, for N = 4, k = 2 and S = {1,2,3}, there are two solutions: {2,2},{1,3}. So output should be 2.
Solution:
int getways(int coins, int target, int total_coins, int *denomination, int size, int idx)
{
int sum = 0, i;
if (coins > target || total_coins < 0)
return 0;
if (target == coins && total_coins == 0)
return 1;
if (target == coins && total_coins < 0)
return 0;
for (i=idx;i<size;i++) {
sum += getways(coins+denomination[i], target, total_coins-1, denomination, size, i);
}
return sum;
}
int main()
{
int target = 49;
int total_coins = 15;
int denomination[] = {1, 2, 3, 4, 5};
int size = sizeof(denomination)/sizeof(denomination[0]);
printf("%d\n", getways(0, target, total_coins, denomination, size, 0));
}
Above is recursive solution. However i need help with my dynamic programming solution:
Let dp[i][j][k] represent sum up to i with j elements and k coins.
So,
dp[i][j][k] = dp[i][j-1][k] + dp[i-a[j]][j][k-1]
Is my recurrence relation right?
I don't really understand your recurrence relation:
Let dp[i][j][k] represent sum up to i with j elements and k coins.
I think you're on the right track, but I suggest simply dropping the middle dimension [j], and use dp[sum][coinsLeft] as follows:
dp[0][0] = 1 // coins: 0, desired sum: 0 => 1 solution
dp[i][0] = 0 // coins: 0, desired sum: i => 0 solutions
dp[sum][coinsLeft] = dp[sum - S1][coinsLeft-1]
+ dp[sum - S2][coinsLeft-1]
+ ...
+ dp[sum - SM][coinsLeft-1]
The answer is then to be found at dp[N][K] (= number of ways to add K coins to get N cents)
Here's some sample code (I advice you to not look until you've tried to solve it yourself. It's a good exercise):
public static int combinations(int numCoinsToUse, int targetSum, int[] denom) {
// dp[numCoins][sum] == ways to get sum using numCoins
int[][] dp = new int[numCoinsToUse+1][targetSum];
// Any sum (except 0) is impossible with 0 coins
for (int sum = 0; sum < targetSum; sum++) {
dp[0][sum] = sum == 0 ? 1 : 0;
}
// Gradually increase number of coins
for (int c = 1; c <= numCoinsToUse; c++)
for (int sum = 0; sum < targetSum; sum++)
for (int d : denom)
if (sum >= d)
dp[c][sum] += dp[c-1][sum - d];
return dp[numCoinsToUse][targetSum-1];
}
Using your example input:
combinations(2, 4, new int[] {1, 2, 3} ) // gives 2

Longest Common Prefix property

I was going through suffix array and its use to compute longest common prefix of two suffixes.
The source says:
"The lcp between two suffixes is the minimum of the lcp's of all pairs of adjacent suffixes between them on the array"
i.e. lcp(x,y)=min{ lcp(x,x+1),lcp(x+1,x+2),.....,lcp(y-1,y) }
where x and y are two index of the string from where the two suffix of the string starts.
I am not convinced with the statement as in example of string "abca".
lcp(1,4)=1 (considering 1 based indexing)
but if I apply the above equation then
lcp(1,4)=min{lcp(1,2),lcp(2,3),lcp(3,4)}
and I think lcp(1,2)=0.
so the answer must be 0 according to the equation.
Am i getting it wrong somewhere?
I think the index referred by the source is not the index of the string itself, but index of the sorted suffixes.
a
abca
bca
ca
Hence
lcp(1,2) = lcp(a, abca) = 1
lcp(1,4) = min(lcp(1,2), lcp(2,3), lcp(3,4)) = 0
You can't find LCP of any two suffixes by simply calculating the minimum of the lcp's of all pairs of adjacent suffixes between them on the array.
We can calculate the LCPs of any suffixes (i,j)
with the Help of Following :
LCP(suffix i,suffix j)=LCP[RMQ(i + 1; j)]
Also Note (i<j) as LCP (suff i,suff j) may not necessarly equal LCP (Suff j,suff i).
RMQ is Range Minimum Query .
Page 3 of this paper.
Details:
Step 1:
First Calculate LCP of Adjacents /consecutive Suffix Pairs .
n= Length of string.
suffixArray[] is Suffix array.
void calculateadjacentsuffixes(int n)
{
for (int i=0; i<n; ++i) Rank[suffixArray[i]] = i;
Height[0] = 0;
for (int i=0, h=0; i<n; ++i)
{
if (Rank[i] > 0)
{
int j = suffixArray[Rank[i]-1];
while (i + h < n && j + h < n && str[i+h] == str[j+h])
{
h++;
}
Height[Rank[i]] = h;
if (h > 0) h--;
}
}
}
Note: Height[i]=LCPs of (Suffix i-1 ,suffix i) ie. Height array contains LCP of adjacent suffix.
Step 2:
Calculate LCP of Any two suffixes i,j using RMQ concept.
RMQ pre-compute function:
void preprocesses(int N)
{
int i, j;
//initialize M for the intervals with length 1
for (i = 0; i < N; i++)
M[i][0] = i;
//compute values from smaller to bigger intervals
for (j = 1; 1 << j <= N; j++)
{
for (i = 0; i + (1 << j) - 1 < N; i++)
{
if (Height[M[i][j - 1]] < Height[M[i + (1 << (j - 1))][j - 1]])
{
M[i][j] = M[i][j - 1];
}
else
{
M[i][j] = M[i + (1 << (j - 1))][j - 1];
}
}
}
}
Step 3: Calculate LCP between any two Suffixes i,j
int LCP(int i,int j)
{
/*Make sure we send i<j always */
/* By doing this ,it resolve following
suppose ,we send LCP(5,4) then it converts it to LCP(4,5)
*/
if(i>j)
swap(i,j);
/*conformation over*/
if(i==j)
{
return (Length_of_str-suffixArray[i]);
}
else
{
return Height[RMQ(i+1,j)];
//LCP(suffix i,suffix j)=LCPadj[RMQ(i + 1; j)]
//LCPadj=LCP of adjacent suffix =Height.
}
}
Where RMQ function is:
int RMQ(int i,int j)
{
int k=log((double)(j-i+1))/log((double)2);
int vv= j-(1<<k)+1 ;
if(Height[M[i][k]]<=Height[ M[vv][ k] ])
return M[i][k];
else
return M[ vv ][ k];
}
Refer Topcoder tutorials for RMQ.
You can check the complete implementation in C++ at my blog.

Finding similar/related texts algorithms

I searched a lot in stackoverflow and Google but I didn't find the best answer for this.
Actually, I'm going to develop a news reader system that crawl and collect news from web (with a crawler) and then, I want to find similar or related news in websites (In order to prevent showing duplicated news in website)
I think the best live example for that is Google News, it collect news from web and then categorize and find related news and articles. This is what I want to do.
What's the best algorithm for doing this?
A relatively simple solution is to compute a tf-idf vector (en.wikipedia.org/wiki/Tf*idf) for each document, then use the cosine distance (en.wikipedia.org/wiki/Cosine_similarity) between these vectors as an estimate for semantic distance between articles.
This will probably capture semantic relationships better than Levenstein distance and is much faster to compute.
This is one: http://en.wikipedia.org/wiki/Levenshtein_distance
public static SqlInt32 ComputeLevenstheinDistance(SqlString firstString, SqlString secondString)
{
int n = firstString.Value.Length;
int m = secondString.Value.Length;
int[,] d = new int[n + 1,m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (int i = 0; i <= n; d[i, 0] = i++)
{
}
for (int j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
int cost = (secondString.Value[j - 1] == firstString.Value[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
This is handy for the task at hand: http://code.google.com/p/boilerpipe/
Also, if you need to reduce the number of words to analyze, try this: http://ots.codeplex.com/
I have found the OTS VERY useful in sentiment analysis, whereby I can reduce the number of sentences into a small list of common phrases and/or words and calculate the overall sentiment based on this. The same should work for similarity.

Resources