Dynamic Programming | Set 14 (Maximum Sum Increasing Subsequence)
Given an array of n positive integers. Write a program to find the sum of maximum sum subsequence of the given array such that the intgers in the subsequence are sorted in increasing order. For example, if input is {1, 101, 2, 3, 100, 4, 5}, then output should be 106 (1 + 2 + 3 + 100), if the input array is {3, 4, 5, 10}, then output should be 22 (3 + 4 + 5 + 10) and if the input array is {10, 5, 4, 3}, then output should be 10
Solution
This problem is a variation of standard Longest Increasing Subsequence (LIS) problem. We need a slight change in the Dynamic Programming solution of LIS problem. All we need to change is to use sum as a criteria instead of length of increasing subsequence.
Following is C implementation for Dynamic Programming solution of the problem.
/* Dynamic Programming implementation of Maximum Sum Increasing
Subsequence (MSIS) problem */
#include<stdio.h>
/* maxSumIS() returns the maximum sum of increasing subsequence in arr[] of
size n */
int maxSumIS( int arr[], int n )
{
int *msis, i, j, max = 0;
msis = (int*) malloc ( sizeof( int ) * n );
/* Initialize msis values for all indexes */
for ( i = 0; i < n; i++ )
msis[i] = arr[i];
/* Compute maximum sum values in bottom up manner */
for ( i = 1; i < n; i++ )
for ( j = 0; j < i; j++ )
if ( arr[i] > arr[j] && msis[i] < msis[j] + arr[i])
msis[i] = msis[j] + arr[i];
/* Pick maximum of all msis values */
for ( i = 0; i < n; i++ )
if ( max < msis[i] )
max = msis[i];
/* Free memory to avoid memory leak */
free( msis );
return max;
}
/* Driver program to test above function */
int main()
{
int arr[] = {1, 101, 2, 3, 100, 4, 5};
int n = sizeof(arr)/sizeof(arr[0]);
printf("Sum of maximum sum increasing subsequence is %d\n",
maxSumIS( arr, n ) );
getchar();
return 0;
}
Time Complexity: O(n^2)
Source: Maximum Sum Increasing Subsequence Problem
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Intelligent
/* Paste your code here (You may delete these lines if not writing code) */ #include<stdio.h> int maxSumIS(int a[],int n){ int temp[n],i,j,sum,max = 0; memset(temp,-1,n); for(i=n-1;i>=0;i--){ sum = 0; for(j=0;j<=i;j++){ if(a[i]>=a[j]){ sum = sum + a[j]; } } temp[i] = sum; } for(i =0;i<n;i++){ if(temp[i]>max){ max = temp[i]; } } return max; } int main() { int arr[] = {1, 101, 2, 3, 100, 4, 5}; int n = sizeof(arr)/sizeof(arr[0]); printf("Sum of maximum sum increasing subsequence is %d\n", maxSumIS( arr, n ) ); getchar(); return 0; }** Solution in previous post won't work for input { 1, 11, 2, 3, 15 } and corrected here **
This is much cleaner solution.
Concept:
1. Take an auxiliary array of equal size.
2. At each index compute sum till that point considering only ascending values.
Algorithm:
1. Sum at 0 index is the element value.
2. For subsequent elements compute the sum by adding current element with sum at index whose element
value is smaller and sum is maximum.
public class MaxSumAscendingSubArray { private void findMaxSum(int[] a) { // initialize sum. this array contains sum at each index considering // only ascending // order values int[] sum = new int[a.length]; int n = a.length - 1; sum[0] = a[0]; for (int i = 1; i <= n; i++) { // let's say sum is the value of the element sum[i] = a[i]; int j = i - 1; // now find the last smaller element and then take sum till that // point and // add to current sum int lastMaxSum = 0; while (j >= 0) { if (a[i] > a[j]) { if (sum[j] > lastMaxSum) { lastMaxSum = sum[j]; } } j--; } sum[i] = sum[i] + lastMaxSum; } // find the max sum from sum auxiliary array int max = 0; for (int i = 0; i <= n; i++) { if (sum[i] > max) { max = sum[i]; } } System.out.println("max sum: " + max); } public static void main(String[] args) { MaxSumAscendingSubArray ms = new MaxSumAscendingSubArray(); ms.findMaxSum(new int[] { 1, 101, 2, 3, 100, 4, 5 }); ms.findMaxSum(new int[] { 3, 4, 5, 10 }); ms.findMaxSum(new int[] { 10, 5, 4, 3 }); ms.findMaxSum(new int[] { 1, 11, 2, 3, 15 }); } }This is much cleaner solution.
Concept:
1. Take an auxiliary array of equal size.
2. At each index compute sum till that point considering only ascending values.
Algorithm:
1. Sum at 0 index is the element value.
2. For subsequent elements compute the sum by adding current element with sum at last index whose element
value is smaller.
public class MaxSumAscendingSubArray { private void findMaxSum(int[] a) { // initialize sum. this array contains sum at each index considering // only ascending // order values int[] sum = new int[a.length]; int n = a.length - 1; sum[0] = a[0]; for (int i = 1; i <= n; i++) { // let's say sum is the value of the element sum[i] = a[i]; int j = i - 1; // now find the last smaller element and then take sum till that // point and // add to current sum while (j >= 0) { if (a[i] > a[j]) { sum[i] = sum[i] + sum[j]; break; } j--; } } // find the max sum from sum auxiliary array int max = 0; for (int i = 0; i <= n; i++) { if (sum[i] > max) { max = sum[i]; } } System.out.println("max sum: " + max); } public static void main(String[] args) { MaxSumAscendingSubArray ms = new MaxSumAscendingSubArray(); ms.findMaxSum(new int[] { 1, 101, 2, 3, 100, 4, 5 }); ms.findMaxSum(new int[] { 3, 4, 5, 10 }); ms.findMaxSum(new int[] { 10, 5, 4, 3 }); } }Hey friends,
Why cant we use stack for finding the max contiguous sum.
- we can insert in stack as we go from left to right
- check if element is less than top of stack
- if the current element is > top of stack , pop it and push current element
- if current element is less than top, push it on stack
- if the current element is < top of stack and after popping stack becomes empty , we dont pop the stack
Does something like above work ?
/* Paste your code here (You may delete these lines if not writing code) */
can this problem be solved in O(nlogn) as the lis problem???
Is it increasing sequence or increasing subsequence?
increasing subsequence
the code is not working for input[1,11,2,3,15] the output should be 2+3+15=20... But its showing 27 ...... please explain why this is happening....
Thanks in advance
Take a closer look at the problem statement and given examples. 27(1+11+15) is the correct answer for your input array.
import java.util.HashMap; public class MaximumSumIncreasingSubSequence { public static CalculatedValues cv = new CalculatedValues(); public static void main(String[] args) { int array[] = { 104, 101, 2, 3, 100, 4, 5 }; IncreasingSubSequenceObject iso = IncreasingSubSequence(array, 0, array.length - 1); System.out.println(iso); } private static IncreasingSubSequenceObject IncreasingSubSequence( int[] array, int low, int high) { if (low == high) { IncreasingSubSequenceObject returnObj = new IncreasingSubSequenceObject(); returnObj.sum = array[low]; returnObj.minPos = low; return returnObj; } int curr = array[low]; IncreasingSubSequenceObject maxIso = new IncreasingSubSequenceObject(); maxIso.sum = curr; maxIso.minPos = low; for (int i = low + 1; i <= high; i++) { IncreasingSubSequenceObject iso1 = null; if (!cv.containsKey(i)) { iso1 = IncreasingSubSequence(array, i, high); if (curr < array[i]) { iso1.sum += curr; iso1.minPos = low; } cv.put(i, iso1); } else { iso1 = cv.get(i); } if (maxIso.sum < iso1.sum) { maxIso = iso1; } } return maxIso; } } class IncreasingSubSequenceObject { int sum = 0; int length = -1; int minPos = -1; int maxPos = -1; public String toString() { return "Sum" + " " + sum + " " + "minPos" + " " + minPos; } } class CalculatedValues extends HashMap<Integer, IncreasingSubSequenceObject> { }First read this post
http://www.geeksforgeeks.org/archives/9591
in which LIS is calculate in O(nlogn) and use that approach to obtain MSIS .
Take another array of length n sum[i] which stores the maximum sum that can be obtained for a particular length of subsequence
1. If A[i] is smallest among all end candidates of active lists, we will start new active list of length 1 and sum[0]=max{a[0],sum[0]}.
2. If A[i] is largest among all end candidates of active lists, we will clone the largest active list, and extend it by A[i] and update sum[len] for extended list
3. If A[i] is in between, we will find a list with largest end element that is smaller than A[i]. Clone and extend this list by A[i]. We will discard all other lists of same length as that of this modified list and also update sum[len] .
and in the end search for maximum sum in the sum[] and that is the required ans thus obtained .
just a problem based on this algo.
http://www.spoj.pl/problems/HOTELS/
oh sry this problem is about subarrays while algo is about LIS .
Instead of using the loops as given in the upper code, we can optimize it further as:
/* for ( i = 1; i < n; i++ ) { for ( j = i-1; j >= 0; j-- ) if ( arr[i] > arr[j] && msis[i] < msis[j] + arr[i]) { msis[i] = msis[j] + arr[i]; break; } printf("%d \n",msis[i]); } */well this works fine !!
algorithm is correct. but i can see in maxSumIS() function is returning local variable i.e "max" . if you are freeing m/m at the end of the function then i guess returning local variable is not a good practice as it may result in returning some garbage value.
I think you are getting confused here. Returning pointer to local variable is not good practice. But, returning a local variable is always fine.
INSTEAD OF USING THIS FORM OF SECOND LOOP
for ( i = 1; i < n; i++ )
for ( j = 0; j arr[j] && msis[i] < msis[j] + arr[i])
msis[i] = msis[j] + arr[i];
WE CAN USE
for ( i = 1; i = 0; j-- )
if ( arr[i] > arr[j] && msis[i] < msis[j] + arr[i])
{
msis[i] = msis[j] + arr[i];
break;
}
@Mukul: Please take a closer look at the problem and examples. This optimization is not possible as we may not got optimal value for many cases.