I'm trying to write a Newton Solver with gsl. It's a system of two equations that take cartesian coordinate (x, y) and translate them into two angles (it's for a robot arm project I'm building; these angles are sent to the stepper motors to move the effector to the cartesian input coordinates).
Here is my function:
int
calc_angles(gsl_vector* coords, gsl_vector* result_angles)
{
const gsl_multiroot_fdfsolver_type* T;
gsl_multiroot_fdfsolver* s;
int status;
size_t i, iter = 0;
const size_t n = 2;
// coordinates whose's angles is to be found
struct rparams p = { gsl_vector_get(coords, 0), gsl_vector_get(coords, 1) };
gsl_multiroot_function_fdf f = { &coords_f,
&coords_df,
&coords_fdf,
n, &p};
// TODO: calculate inital guess
double angles_init[2] = { 140.0*M_PI/180.0, 30*M_PI/180.0 };
gsl_vector* angles = gsl_vector_alloc(n);
gsl_vector_set(angles, 0, angles_init[0]);
gsl_vector_set(angles, 1, angles_init[1]);
T = gsl_multiroot_fdfsolver_gnewton;
s = gsl_multiroot_fdfsolver_alloc(T, n);
gsl_multiroot_fdfsolver_set(s, &f, angles);
print_state(iter, s);
do
{
iter++;
status = gsl_multiroot_fdfsolver_iterate(s);
print_state(iter, s);
if(status) { break; }
status = gsl_multiroot_test_residual(s->f, 1e-7);
} while (status == GSL_CONTINUE && iter < 1000);
printf("status = %s\n", gsl_strerror(status));
print_state(iter, s);
// store results in result_angles
gsl_vector_memcpy(result_angles, angles);
// sanity check
if(gsl_vector_equal(result_angles, angles))
{
printf("Vectors are equal\n");
}
gsl_multiroot_fdfsolver_free(s);
gsl_vector_free(angles);
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
print_state(size_t iter, gsl_multiroot_fdfsolver* s)
{
printf("iter = %3u x = % .6f % .6f "
"f(x) = % .3e % .3e\n",
iter,
gsl_vector_get(s->x, 0),
gsl_vector_get(s->x, 1),
gsl_vector_get(s->f, 0),
gsl_vector_get(s->f, 1) );
// all good, return success
return GSL_SUCCESS;
}
The function calc_angles takes two vectors, one with the input coordinates that are used to calculate the angles I'm looking for, and a second vector where I want to store said angles. Now, this works as expected and the function does calculate the correct angles for my input cartesian coordinates (I haven't implemented the input reading function yet; so I'm using hard coded values for testing).
Here's my problem: when I call calc_angles in my main function, when I return to main and try to print the resulting angles, they no longer match the calculated values:
int
main(int argc, char* argv[])
{
const size_t n = 2;
// initialize vectors: input coords, initial guess, result angles
gsl_vector* coords = gsl_vector_alloc(n);
gsl_vector* result_angles = gsl_vector_alloc(n);
gsl_vector_set(result_angles, 0, 0.0); // set result angles to zero
gsl_vector_set(result_angles, 1, 0.0);
// TODO: read coordinates from input
// get_coords(coords);
gsl_vector_set(coords, 0, 0.0);
gsl_vector_set(coords, 1, 8.6);
// calc new angles
if(calc_angles(coords, result_angles)) { printf("calc_angles worked"); }
// output new angles
printf("Calculated angles: alpha: % .6f, beta: % .6f\n",
gsl_vector_get(result_angles, 0),
gsl_vector_get(result_angles, 1) );
// deallocate memory
gsl_vector_free(coords);
gsl_vector_free(result_angles);
return 0;
}
Here's the output of the program:
./bin/example_app
iter = 0 x = 2.443461 0.523599 f(x) = 9.998e-02 -2.905e-01
iter = 1 x = 2.308197 0.897453 f(x) = -4.876e-02 8.863e-02
iter = 2 x = 2.336417 0.808354 f(x) = -2.295e-03 1.077e-02
iter = 3 x = 2.342411 0.799205 f(x) = -1.653e-05 2.539e-04
iter = 4 x = 2.342579 0.799014 f(x) = -2.884e-09 3.705e-06
iter = 5 x = 2.342582 0.799011 f(x) = -7.438e-15 5.048e-08
status = success
iter = 5 x = 2.342582 0.799011 f(x) = -7.438e-15 5.048e-08
Vectors are equal
Calculated angles: alpha: 2.443461, beta: 0.523599
You can see that alpha and beta don't match the calculated values any longer. I used gdb to check the memory locations, the values didn't change (so gsl_vector_memcpy() does work correctly). So I assume it's something with printf that isn't working. What am I missing?
I'm new to gsl. Here's the full source code (copied into one file for simplicity):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_sf.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_multiroots.h>
// constants
const double LENGTH = 6.0;
const double TOL = 1.0e-6;
// params struct
struct rparams
{
double x, y;
};
// calculate the primary and secondary angles for the given coordinates in coords
int calc_angles(gsl_vector* coords, gsl_vector* result_angles);
int coords_f(const gsl_vector* angles, void* params, gsl_vector* f);
int coords_df(const gsl_vector* angles, void* params, gsl_matrix* J);
int coords_fdf(const gsl_vector* angles, void* params, gsl_vector* f, gsl_matrix* J);
// IO functions
int get_coords(gsl_vector* coords);
// helper/debug functions
int print_state(size_t iter, gsl_multiroot_fdfsolver* s);
int
main(int argc, char* argv[])
{
const size_t n = 2;
// initialize vectors: input coords, initial guess, result angles
gsl_vector* coords = gsl_vector_alloc(n);
gsl_vector* result_angles = gsl_vector_alloc(n);
gsl_vector_set(result_angles, 0, 0.0); // set result angles to zero
gsl_vector_set(result_angles, 1, 0.0);
// TODO: read coordinates from input
// get_coords(coords);
gsl_vector_set(coords, 0, 0.0);
gsl_vector_set(coords, 1, 8.6);
// calc new angles
if(calc_angles(coords, result_angles)) { printf("calc_angles worked"); }
// output new angles
printf("Calculated angles: alpha: % .6f, beta: % .6f\n",
gsl_vector_get(result_angles, 0),
gsl_vector_get(result_angles, 1) );
// deallocate memory
gsl_vector_free(coords);
gsl_vector_free(result_angles);
return 0;
}
//------------------------------------------------------------------------------
int
calc_angles(gsl_vector* coords, gsl_vector* result_angles)
{
const gsl_multiroot_fdfsolver_type* T;
gsl_multiroot_fdfsolver* s;
int status;
size_t i, iter = 0;
const size_t n = 2;
// coordinates whose's angles is to be found
struct rparams p = { gsl_vector_get(coords, 0), gsl_vector_get(coords, 1) };
gsl_multiroot_function_fdf f = { &coords_f,
&coords_df,
&coords_fdf,
n, &p};
// TODO: calculate inital guess
double angles_init[2] = { 140.0*M_PI/180.0, 30*M_PI/180.0 };
gsl_vector* angles = gsl_vector_alloc(n);
gsl_vector_set(angles, 0, angles_init[0]);
gsl_vector_set(angles, 1, angles_init[1]);
T = gsl_multiroot_fdfsolver_gnewton;
s = gsl_multiroot_fdfsolver_alloc(T, n);
gsl_multiroot_fdfsolver_set(s, &f, angles);
print_state(iter, s);
do
{
iter++;
status = gsl_multiroot_fdfsolver_iterate(s);
print_state(iter, s);
if(status) { break; }
status = gsl_multiroot_test_residual(s->f, 1e-7);
} while (status == GSL_CONTINUE && iter < 1000);
printf("status = %s\n", gsl_strerror(status));
print_state(iter, s);
// store results in result_angles
gsl_vector_memcpy(result_angles, angles);
// sanity check
if(gsl_vector_equal(result_angles, angles))
{
printf("Vectors are equal\n");
}
gsl_multiroot_fdfsolver_free(s);
gsl_vector_free(angles);
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
coords_f(const gsl_vector* angles, void* params, gsl_vector* f)
{
// extract c and y coordinates
double x = ((struct rparams*) params)->x;
double y = ((struct rparams*) params)->y;
// extract input angles
const double alpha = gsl_vector_get(angles, 0);
const double beta = gsl_vector_get(angles, 1);
// calculate coordinates from angles
const double x0 = gsl_sf_cos(alpha) + gsl_sf_cos(beta) - x / LENGTH;
const double y0 = gsl_sf_sin(alpha) + gsl_sf_sin(beta) - y / LENGTH;
// save results
gsl_vector_set(f, 0, x0);
gsl_vector_set(f, 1, y0);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
coords_df(const gsl_vector* angles, void* params, gsl_matrix* J)
{
// extract input angle
const double alpha = gsl_vector_get(angles, 0);
const double beta = gsl_vector_get(angles, 1);
// calculate partial derivatives for Jacobian matrix
const double df00 = -gsl_sf_sin(alpha);
const double df01 = -gsl_sf_sin(beta);
const double df10 = gsl_sf_cos(alpha);
const double df11 = gsl_sf_sin(beta);
// set Jacobian matrix
gsl_matrix_set(J, 0, 0, df00);
gsl_matrix_set(J, 0, 1, df01);
gsl_matrix_set(J, 1, 0, df10);
gsl_matrix_set(J, 1, 1, df11);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
coords_fdf(const gsl_vector* angles, void* params, gsl_vector* f, gsl_matrix* J)
{
coords_f(angles, params, f);
coords_df(angles, params, J);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
get_coords(gsl_vector* coords)
{
// TODO: replace with platform specific code
// read new coordinates from input
float x, y;
printf("Enter new X coordinate: ");
scanf("%f", &x);
printf("Enter new Y coordinate: ");
scanf("%f", &y);
// TODO: check for legal input bounds
// store input in memory
gsl_vector_set(coords, 0, x);
gsl_vector_set(coords, 1, y);
printf("x: %3.3f, y: %3.3f\n", x, y);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
print_state(size_t iter, gsl_multiroot_fdfsolver* s)
{
printf("iter = %3u x = % .6f % .6f "
"f(x) = % .3e % .3e\n",
iter,
gsl_vector_get(s->x, 0),
gsl_vector_get(s->x, 1),
gsl_vector_get(s->f, 0),
gsl_vector_get(s->f, 1) );
// all good, return success
return GSL_SUCCESS;
}
Short answer: s -> x stores the state of the solver, you shouldn't use the input array angles to get the output. This is the result of your code after I fixed a couple of minor details
iter = 0 x = 2.443461 0.523599 f(x) = 9.998e-02 -2.905e-01
iter = 1 x = 2.308197 0.897453 f(x) = -4.876e-02 8.863e-02
iter = 2 x = 2.336417 0.808354 f(x) = -2.295e-03 1.077e-02
iter = 3 x = 2.342411 0.799205 f(x) = -1.653e-05 2.539e-04
iter = 4 x = 2.342579 0.799014 f(x) = -2.884e-09 3.705e-06
iter = 5 x = 2.342582 0.799011 f(x) = -7.438e-15 5.048e-08
status = success
iter = 5 x = 2.342582 0.799011 f(x) = -7.438e-15 5.048e-08
calc_angles worked
Calculated angles: alpha: 2.342582, beta: 0.799011
And here is the actual code
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_multiroots.h>
#include <gsl/gsl_sf.h>
// constants
const double LENGTH = 6.0;
const double TOL = 1.0e-6;
// params struct
struct rparams
{
double x, y;
};
// calculate the primary and secondary angles for the given coordinates in coords
int calc_angles(gsl_vector* coords, gsl_vector* result_angles);
int coords_f(const gsl_vector* angles, void* params, gsl_vector* f);
int coords_df(const gsl_vector* angles, void* params, gsl_matrix* J);
int coords_fdf(const gsl_vector* angles, void* params, gsl_vector* f, gsl_matrix* J);
// IO functions
int get_coords(gsl_vector* coords);
// helper/debug functions
int print_state(size_t iter, gsl_multiroot_fdfsolver* s);
int
main(int argc, char* argv[])
{
const size_t n = 2;
// initialize vectors: input coords, initial guess, result angles
gsl_vector* coords = gsl_vector_alloc(n);
gsl_vector* result_angles = gsl_vector_alloc(n);
gsl_vector_set(result_angles, 0, 0.0); // set result angles to zero
gsl_vector_set(result_angles, 1, 0.0);
// TODO: read coordinates from input
// get_coords(coords);
gsl_vector_set(coords, 0, 0.0);
gsl_vector_set(coords, 1, 8.6);
// calc new angles
if(!calc_angles(coords, result_angles)) { printf("calc_angles worked\n"); }
// output new angles
printf("Calculated angles: alpha: % .6f, beta: % .6f\n",
gsl_vector_get(result_angles, 0),
gsl_vector_get(result_angles, 1) );
// deallocate memory
gsl_vector_free(coords);
gsl_vector_free(result_angles);
return 0;
}
//------------------------------------------------------------------------------
int
calc_angles(gsl_vector* coords, gsl_vector* result_angles)
{
const gsl_multiroot_fdfsolver_type* T;
gsl_multiroot_fdfsolver* s;
int status;
size_t iter = 0;
const size_t n = 2;
// coordinates whose's angles is to be found
struct rparams p = { gsl_vector_get(coords, 0), gsl_vector_get(coords, 1) };
gsl_multiroot_function_fdf f = { &coords_f,
&coords_df,
&coords_fdf,
n, &p};
// TODO: calculate inital guess
double angles_init[2] = { 140.0*M_PI/180.0, 30*M_PI/180.0 };
gsl_vector* angles = gsl_vector_alloc(n);
gsl_vector_set(angles, 0, angles_init[0]);
gsl_vector_set(angles, 1, angles_init[1]);
T = gsl_multiroot_fdfsolver_gnewton;
s = gsl_multiroot_fdfsolver_alloc(T, n);
gsl_multiroot_fdfsolver_set(s, &f, angles);
print_state(iter, s);
do
{
iter++;
status = gsl_multiroot_fdfsolver_iterate(s);
print_state(iter, s);
if(status) { break; }
status = gsl_multiroot_test_residual(s->f, 1e-7);
} while (status == GSL_CONTINUE && iter < 1000);
printf("status = %s\n", gsl_strerror(status));
print_state(iter, s);
// store results in result_angles
gsl_vector_memcpy(result_angles, s -> x);
// sanity check
if(gsl_vector_equal(result_angles, angles))
{
printf("Vectors are equal\n");
}
gsl_multiroot_fdfsolver_free(s);
gsl_vector_free(angles);
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
coords_f(const gsl_vector* angles, void* params, gsl_vector* f)
{
// extract c and y coordinates
double x = ((struct rparams*) params)->x;
double y = ((struct rparams*) params)->y;
// extract input angles
const double alpha = gsl_vector_get(angles, 0);
const double beta = gsl_vector_get(angles, 1);
// calculate coordinates from angles
const double x0 = gsl_sf_cos(alpha) + gsl_sf_cos(beta) - x / LENGTH;
const double y0 = gsl_sf_sin(alpha) + gsl_sf_sin(beta) - y / LENGTH;
// save results
gsl_vector_set(f, 0, x0);
gsl_vector_set(f, 1, y0);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
coords_df(const gsl_vector* angles, void* params, gsl_matrix* J)
{
// extract input angle
const double alpha = gsl_vector_get(angles, 0);
const double beta = gsl_vector_get(angles, 1);
// calculate partial derivatives for Jacobian matrix
const double df00 = -gsl_sf_sin(alpha);
const double df01 = -gsl_sf_sin(beta);
const double df10 = gsl_sf_cos(alpha);
const double df11 = gsl_sf_sin(beta);
// set Jacobian matrix
gsl_matrix_set(J, 0, 0, df00);
gsl_matrix_set(J, 0, 1, df01);
gsl_matrix_set(J, 1, 0, df10);
gsl_matrix_set(J, 1, 1, df11);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
coords_fdf(const gsl_vector* angles, void* params, gsl_vector* f, gsl_matrix* J)
{
coords_f(angles, params, f);
coords_df(angles, params, J);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
get_coords(gsl_vector* coords)
{
// TODO: replace with platform specific code
// read new coordinates from input
float x, y;
printf("Enter new X coordinate: ");
scanf("%f", &x);
printf("Enter new Y coordinate: ");
scanf("%f", &y);
// TODO: check for legal input bounds
// store input in memory
gsl_vector_set(coords, 0, x);
gsl_vector_set(coords, 1, y);
printf("x: %3.3f, y: %3.3f\n", x, y);
// all good, return success
return GSL_SUCCESS;
}
//------------------------------------------------------------------------------
int
print_state(size_t iter, gsl_multiroot_fdfsolver* s)
{
printf("iter = %3ld x = % .6f % .6f "
"f(x) = % .3e % .3e\n",
iter,
gsl_vector_get(s->x, 0),
gsl_vector_get(s->x, 1),
gsl_vector_get(s->f, 0),
gsl_vector_get(s->f, 1) );
// all good, return success
return GSL_SUCCESS;
}
Given an array of positive integers, what's the most efficient algorithm to find non-consecutive elements from this array which, when added together, produce the maximum sum?
Dynamic programming? Given an array A[0..n], let M(i) be the optimal solution using the elements with indices 0..i. Then M(-1) = 0 (used in the recurrence), M(0) = A[0], and M(i) = max(M(i - 1), M(i - 2) + A[i]) for i = 1, ..., n. M(n) is the solution we want. This is O(n). You can use another array to store which choice is made for each subproblem, and so recover the actual elements chosen.
Let A be the given array and Sum be another array such that Sum[i] represents the maximum sum of non-consecutive elements from arr[0]..arr[i].
We have:
Sum[0] = arr[0]
Sum[1] = max(Sum[0],arr[1])
Sum[2] = max(Sum[0]+arr[2],Sum[1])
...
Sum[i] = max(Sum[i-2]+arr[i],Sum[i-1]) when i>=2
If size is the number of elements in arr then sum[size-1] will be the answer.
One can code a simple recursive method in top down order as:
int sum(int *arr,int i) {
if(i==0) {
return arr[0];
}else if(i==1) {
return max(arr[0],arr[1]);
}
return max(sum(arr,i-2)+arr[i],sum(arr,i-1));
}
The above code is very inefficient as it makes exhaustive duplicate recursive calls. To avoid this we use memoization by using an auxiliary array called sum as:
int sum(int *arr,int size) {
int *sum = malloc(sizeof(int) * size);
int i;
for(i=0;i<size;i++) {
if(i==0) {
sum[0] = arr[0];
}else if(i==1) {
sum[1] = max(sum[0],arr[1]);
}else{
sum[i] = max(sum[i-2]+arr[i],sum[i-1]);
}
}
return sum[size-1];
}
Which is O(N) in both space and time.
O(N) in time and O(1) in space (DP) solution:
int dp[2] = {a[0], a[1]};
for(int i = 2; i < a.size(); i++)
{
int temp = dp[1];
dp[1] = dp[0] + a[i];
dp[0] = max(dp[0], temp);
}
int answer = max(dp[0], dp[1]);
/**
* Given an array of positive numbers, find the maximum sum of elements such
* that no two adjacent elements are picked
* Top down dynamic programming approach without memorisation.
* An alternate to the bottom up approach.
*/
public class MaxSumNonConsec {
public static int maxSum(int a[], int start, int end) {
int maxSum = 0;
// Trivial cases
if (start == end) {
return a[start];
} else if (start > end) {
return 0;
} else if (end - start == 1) {
return a[start] > a[end] ? a[start] : a[end];
} else if (start < 0) {
return 0;
} else if (end >= a.length) {
return 0;
}
// Subproblem solutions, DP
for (int i = start; i <= end; i++) {
int possibleMaxSub1 = maxSum(a, i + 2, end);
int possibleMaxSub2 = maxSum(a, start, i - 2);
int possibleMax = possibleMaxSub1 + possibleMaxSub2 + a[i];
if (possibleMax > maxSum) {
maxSum = possibleMax;
}
}
return maxSum;
}
public static void main(String args[]) {
int a[] = { 8, 6, 11, 10, 11, 10 };
System.out.println(maxSum(a, 0, a.length - 1));
}
}
The solution by #Ismail Badawi does not seem to work in the following case: Let us take the array: 8, 3, 1, 7 Then in this case, the algo returns max sum = 9 whereas it should be 15.
A solution to correct it is given an array A[0..n], let M(i) be the optimal solution using the elements with indices 0..i. Then M(0) = A[0], and M(i) = max(M(i - 1), M(i - 2) + A[i], M(i-3) + A[i]) for i = 3, ..., n. M(n) is the solution we want. This is O(n).
IIUC: say your array is 1,2,3,4,5 then 3+5 would be 'correct' and 4+5 not, this means you'll have to find the largest numbers and check if they are consecutive. So an algorithm would be to make use of a second array, for the number of elements you need to add which you fill by traversing the original array and finding the largest non-consecutive integers, then add this up.
For the above array I guess [1,3], [1,4], [1,5], [1,3,5], [2,4], [2,5], [3,5] would be valid non-consecutive integers to be summed, the max sum would be 9 in this case [1,3,5]. So, to adapt the above algorithm, I would suggest you step through the array using several temporary arrays to find all the non-consecutive integer lists, and then check which is the largest. Keep in mind that 'most elements' does not mean 'largest sum'.
Dynamic programming solution is the most elegant of all.
And it serves for any value of the distance between two numbers that should not be considered.
But for k= 1, which is for consecutive numbers constraint, I tried using backtracking.
There are different patterns to be compared for the maximum sum. Below is the list :
Number of patterns for 1 = 1
[1]
Number of patterns for 2 = 2
[1][2]
Number of patterns for 3 = 2
[1, 3][2]
Number of patterns for 4 = 3
[1, 3][1, 4][2, 4]
Number of patterns for 5 = 4
[1, 3, 5][1, 4][2, 4][2, 5]
Number of patterns for 6 = 5
[1, 3, 5][1, 3, 6][1, 4, 6][2, 4, 6][2, 5]
Number of patterns for 7 = 7
[1, 3, 5, 7][1, 3, 6][1, 4, 6][1, 4, 7][2, 4, 6][2, 4, 7][2, 5, 7]
Number of patterns for 8 = 9
[1, 3, 5, 7][1, 3, 5, 8][1, 3, 6, 8][1, 4, 6, 8][1, 4, 7][2, 4, 6, 8][2, 4, 7][2, 5, 7][2, 5, 8]
Number of patterns for 9 = 12
[1, 3, 5, 7, 9][1, 3, 5, 8][1, 3, 6, 8][1, 3, 6, 9][1, 4, 6, 8][1, 4, 6, 9][1, 4, 7, 9][2, 4, 6, 8][2, 4, 6, 9][2, 4, 7, 9][2, 5, 7, 9][2, 5, 8]
Following is the code in java:
public class MaxSeqRecursive {
private static int num = 5;
private static int[] inputArry = new int[] { 1,3,9,20,7 };
private static Object[] outArry;
private static int maxSum = 0;
public static void main(String[] args) {
List<Integer> output = new ArrayList<Integer>();
output.add(1);
convert(output, -1);
for (int i = 0; i < outArry.length; i++) {
System.out.print(outArry[i] + ":");
}
System.out.print(maxSum);
}
public static void convert( List<Integer> posArry, int prevValue) {
int currentValue = -1;
if (posArry.size() == 0) {
if (prevValue == 2) {
return;
} else {
posArry.add(2);
prevValue = -1;
}
}
currentValue = (int) posArry.get(posArry.size() - 1);
if (currentValue == num || currentValue == num - 1) {
updateMax(posArry);
prevValue = (int) posArry.get(posArry.size() - 1);
posArry.remove(posArry.size() - 1);
} else {
int returnIndx = getNext(posArry, prevValue);
if (returnIndx == -2)
return;
if (returnIndx == -1) {
prevValue = (int) posArry.get(posArry.size() - 1);
posArry.remove(posArry.size() - 1);
} else {
posArry.add(returnIndx);
prevValue = -1;
}
}
convert(posArry, prevValue);
}
public static int getNext( List<Integer> posArry, int prevValue) {
int currIndx = posArry.size();
int returnVal = -1;
int value = (int) posArry.get(currIndx - 1);
if (prevValue < num) {
if (prevValue == -1)
returnVal = value + 2;
else if (prevValue - value < 3)
returnVal = prevValue + 1;
else
returnVal = -1;
}
if (returnVal > num)
returnVal = -1;
return returnVal;
}
public static void updateMax(List posArry) {
int sum = 0;
for (int i = 0; i < posArry.size(); i++) {
sum = sum + inputArry[(Integer) posArry.get(i) - 1];
}
if (sum > maxSum) {
maxSum = sum;
outArry = posArry.toArray();
}
}
}
Time complexity: O( number of patterns to be compared)
Another Java Implementation ( runs in linear time )
public class MaxSum {
private static int ofNonConsecutiveElements (int... elements) {
int maxsofar,maxi2,maxi1;
maxi1 = maxsofar = elements[0];
maxi2 = 0;
for (int i = 1; i < elements.length; i++) {
maxsofar = Math.max(maxi2 + elements[i], maxi1);
maxi2 = maxi1;
maxi1 = maxsofar;
}
return maxsofar;
}
public static void main(String[] args) {
System.out.println(ofNonConsecutiveElements(6, 4, 2, 8, 1));
}
}
My solution is O(N) time and O(1) space.
private int largestSumNonConsecutive(int[] a) {
return largestSumNonConsecutive(a, a.length-1)[1];
}
private int[] largestSumNonConsecutive(int[] a, int end) { //returns array largest(end-1),largest(end)
if (end==0) return new int[]{0,a[0]};
int[] largest = largestSumNonConsecutive(a, end-1);
int tmp = largest[1];
largest[1] = Math.max(largest[0] + a[end], largest[1]);
largest[0] = tmp;
return largest;
}
int nonContigousSum(vector<int> a, int n) {
if (n < 0) {
return 0;
}
return std::max(nonContigousSum(a, n - 1), nonContigousSum(a, n - 2) + a[n]);
}
this is the recursive approach with the help of which we can solve this question
(OPTIMAL SUB-STRUCTURE HALLMARK OF DYNAMIC PROGRAMMING.
Here we are considering two cases, in first we exclude a[n] and in the second we include a[n] and return the max of those sub cases found.
We are basically finding all the subsets of the array and returning the length of the non-contiguous array with max sum.
Use tabulation or memoization for avoiding same sub-problems.
A penny from me.
public class Problem {
/**
* Solving by recursion, top down approach. Always try this recursion approach and then go with
* iteration. We have to add dp table to optimize the time complexity.
*/
public static int maxSumRecur(int arr[], int i) {
if(i < 0) return 0;
if(i == 0) return arr[0];
if(i == 1) return Math.max(arr[0], arr[1]);
int includeIthElement = arr[i] + maxSumRecur(arr, i-2);
int excludeIthElement = maxSumRecur(arr, i-1);
return Math.max(includeIthElement, excludeIthElement);
}
/**
* Solving by iteration. Bottom up approach.
*/
public static void maxSumIter(int arr[]) {
System.out.println(Arrays.toString(arr));
int dp[] = new int[arr.length];
dp[0] = arr[0];
dp[1] = Math.max(arr[0], arr[1]);
for(int i=2; i <= arr.length - 1; i++) {
dp[i] = Math.max(arr[i] + dp[i-2], dp[i-1]);
}
System.out.println("Max subsequence sum by Iteration " + dp[arr.length - 1] + "\n");
}
public static void maxSumRecurUtil(int arr[]) {
System.out.println(Arrays.toString(arr));
System.out.println("Max subsequence sum by Recursion " + maxSumRecur(arr, arr.length - 1) +
"\n");
}
public static void main(String[] args) {
maxSumRecurUtil(new int[]{5, 5, 10, 100, 10, 5});
maxSumRecurUtil(new int[]{20, 1, 2, 3});
maxSumIter(new int[]{5, 5, 10, 100, 10, 5});
maxSumIter(new int[]{20, 1, 2, 3});
}
}
Make a list of numbers that is the odd or even sums corresponding to each number so far; e.g. for input of [1,2,4,1,2,3,5,3,1,2,3,4,5,2] the odd-even sums would be [1,2,5,3,7,6,12,9,13,11,16,15,21,17]
Now walk the list backwards greedily summing but skipping those elements whose odd/even sum is less than that of next-to-be-considered element.
src = [1,2,4,1,2,3,5,3,1,2,3,4,5,2]
odd_even_sums = src[:2]
for i in xrange(2,len(src)):
odd_even_sums.append(src[i] + odd_even_sums[i-2])
best = []
for i in xrange(len(src)-1,-1,-1):
if i == 0:
best.append(i)
elif odd_even_sums[i-1] > odd_even_sums[i]:
pass
elif odd_even_sums[i-1] == odd_even_sums[i]:
raise Exception("an exercise for the reader")
else:
best.append(i)
best.reverse()
print "Best:",",".join("%s=%s"%(b,src[b]) for b in best)
print "Scores:",sum(odd_even_sums[b] for b in best)
Outputs:
Best: 0=1,1=2,2=4,4=2,6=5,8=1,10=3,12=5
Scores: 77
public static int findMaxSum(int[] a){
int sum0=0; //will hold the sum till i-2
int sum1=0;//will hold the sum till i-1
for(int k : a){
int x=Math.max(sum0+k, sum1);//max(sum till (i-2)+a[i], sum till (i-1))
sum0=sum1;
sum1=x;
}
return sum1;
}
Below is the crux of algorithm:
max(max sum till (i-2)+a[i], max sum till (i-1))
O(N) time complexity and O(1) space complexity.
A rather naive yet complete implementation.
Recursion equation is T(n) = n^2 + nT(n-3), which if I'm not wrong leads to exponential time. The (n-3) comes from the fact a number cannot add with itself/previous/next numbers.
The program reports the constituent list that makes up the sum (there are multiple, exponentially growing, of these lists, but it just picks one).
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class MaxSumNoAdjacent {
private static class Sum {
int sum;
List<Integer> constituents = new ArrayList<>();
Sum(int sum, List<Integer> constituents) {
this.sum = sum;
this.constituents = constituents;
}
#Override
public String toString() {
return "sum: " + sum + " " + constituents.toString();
}
}
public static Sum maxSum(int[] arr) {
List<Integer> input = new ArrayList<>();
for (int i : arr) {
if (i != Integer.MIN_VALUE) { //Integer.MIN_VALUE indicates unreachability
input.add(i);
}
}
if (input.size() == 0) {
return null;
}
if (input.size() == 1) {
List<Integer> constituents = new ArrayList<>();
constituents.add(input.get(0));
return new Sum(input.get(0), constituents);
}
if (input.size() == 2) {
int max = Math.max(input.get(0), input.get(1));
List<Integer> constituents = new ArrayList<>();
constituents.add(max);
return new Sum(max, constituents);
}
Map<Integer, int[]> numberAndItsReachability = new HashMap<>();
for (int i = 0; i < input.size(); i++) {
int[] neighbours = new int[input.size()];
if (i > 0) {
neighbours[i-1] = Integer.MIN_VALUE; //unreachable to previous
}
if (i < input.size()-1) {
neighbours[i+1] = Integer.MIN_VALUE; //unreachable to next
}
neighbours[i] = Integer.MIN_VALUE; //unreachable to itself
for (int j = 0; j < neighbours.length; j++) {
if (neighbours[j] == 0) {
neighbours[j] = input.get(j); //remember values of reachable neighbours
}
}
numberAndItsReachability.put(input.get(i), neighbours);
}
Sum maxSum = new Sum(Integer.MIN_VALUE, null);
for (Entry<Integer, int[]> pair : numberAndItsReachability.entrySet()) {
Sum sumMinusThisNumber = maxSum(pair.getValue()); //call recursively on its reachable neighbours
if (sumMinusThisNumber != null) {
int candidateSum = sumMinusThisNumber.sum + pair.getKey();
if (maxSum.sum < candidateSum) {
sumMinusThisNumber.constituents.add(pair.getKey());
maxSum = new Sum(candidateSum, sumMinusThisNumber.constituents);
}
}
}
return maxSum;
}
public static void main(String[] args) {
int[] arr1 = {3,2,5,10,7};
int[] arr2 = {3,2,7,10};
int[] arr3 = {5,5,10,40,50,35};
int[] arr4 = {4,4,4,4};
System.out.println(maxSum(arr1).toString());
System.out.println(maxSum(arr2).toString());
System.out.println(maxSum(arr3).toString());
System.out.println(maxSum(arr4).toString());
}
}
Here is a C# version for reference (you may refer to: http://dream-e-r.blogspot.com/2014/07/maximum-sum-of-non-adjacent-subsequence.html):
In-order to solve a problem using dynamic programming there should be a solution which has optimal substructure and overlapping sub problems properties. And the current problem has optimal substructure property.
Say, f(i) is defined as maximum subsequence sum of non adjacent elements for 'i' items, then
f( i) = 0 if i = 0
max (f(i-1), f(i-2) + a[i])
Below is the algorithm for the same (no
te it can solved without the encapsulating data in 'record' - i just preferred it this way) - which should illustrate the above idea:
int FindMaxNonAdjuscentSubsequentSum(int[] a)
{
a.ThrowIfNull("a");
if(a.Length == 0)
{
return 0;
}
Record r = new Record()
{
max_including_item = a[0],
max_excluding_item = 0
};
for (int i = 1; i < a.Length; i++)
{
var t = new Record();
//there will be only two cases
//1. if it includes the current item, max is maximum of non adjuscent sub
//sequence sum so far, excluding the last item
t.max_including_item = r.max_excluding_item + a[i];
//2. if it excludes current item, max is maximum of non adjuscent subsequence sum
t.max_excluding_item = r.Max;
r = t;
}
return r.Max;
}
Unit Tests
[TestMethod]
[TestCategory(Constants.DynamicProgramming)]
public void MaxNonAdjascentSubsequenceSum()
{
int[] a = new int[] { 3, 2, 5, 10, 7};
Assert.IsTrue(15 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 3, 2, 5, 10 };
Assert.IsTrue(13 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 5, 10, 40, 50, 35 };
Assert.IsTrue(80 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 1, -1, 6, -4, 2, 2 };
Assert.IsTrue(9 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 1, 6, 10, 14, -5, -1, 2, -1, 3 };
Assert.IsTrue(25 == this.FindMaxNonAdjuscentSubsequentSum(a));
}
where
public static int Max(int a, int b)
{
return (a > b) ? a : b;
}
class Record
{
public int max_including_item = int.MinValue;
public int max_excluding_item = int.MinValue;
public int Max
{
get
{
return Max(max_including_item, max_excluding_item);
}
}
}
public static int maxSumNoAdj(int[] nums){
int[] dp = new int[nums.length];
dp[0] = Math.max(0, nums[0]); // for dp[0], select the greater value (0,num[0])
dp[1] = Math.max(nums[1], Math.max(0, dp[0]));
int maxSum = Math.max(dp[0], dp[1]);
for(int i = 2; i < nums.length; i++){
int ifSelectCurrent = Math.max(nums[i] + dp[i-2], dp[i-2]);// if select, there are two possible
int ifNotSelectCurrent = Math.max(dp[i-1], dp[i-2]); // if not select, there are two posible
dp[i] = Math.max(ifSelectCurrent, ifNotSelectCurrent); // choose the greater one
maxSum = Math.max(dp[i], maxSum); // update the result
}
return maxSum;
}
public static void main(String[] args) {
int[] nums = {-9, 2, 3, -7, 1, 1};
System.out.println(maxSumNoAdj(nums));
}