Hamsa
Hamsa

Reputation: 483

How to solve this problem through dynamic programming approach?

I was solving a very basic problem on arrays. The problem statement goes like this:

A basketball court has been opened in SIS, so Demid has decided to hold a basketball exercise session. 2⋅n students have come to Demid's exercise session, and he lined up them into two rows of the same size (there are exactly n people in each row). Students are numbered from 1 to n in each row in order from left to right.

Now Demid wants to choose a team to play basketball. He will choose players from left to right, and the index of each chosen player (excluding the first one taken) will be strictly greater than the index of the previously chosen player. To avoid giving preference to one of the rows, Demid chooses students in such a way that no consecutive chosen students belong to the same row. The first student can be chosen among all 2n students (there are no additional constraints), and a team can consist of any number of students.

Demid thinks, that in order to compose a perfect team, he should choose students in such a way, that the total height of all chosen students is maximum possible. Help Demid to find the maximum possible total height of players in a team he can choose.

For example if the input is:(First line contains the value of n, next 2 rows follow which contains the height of the students)

5
9 3 5 7 3
5 8 1 4 5

My approach was:

#These are global variables and functions. 

int arr1[n],arr2[n],sum=0,max=0;
void func1(i)
{
   if(i==n)
   {
      if(sum>max)
         max=sum;
      return;
   }
   sum+=arr1[i];
   for(k=i+1;k<n;k++)
      func2(k);
}

void func2(i)
{
   if(i==n)
   {
      if(sum>max)
         max=sum;
      return;
   }
   sum+=arr2[i];
   for(k=i+1;k<n;k++)
      func1(k);
}

#Caller module. In main
for(i=0;i<n;i++)
{
   sum=0;
   func1(i);
}

This is my algorithm based on my logical reasoning. I have not coded it yet, will code it later. So feel free to point out any logical errors in the code.

I know this can be solved easily using dynamic programming approach and this algorithm is not quite it. How will the functions look like in that case?

As far as I can point out, the problem in this algorithm is I need to declare arr1 and arr2 globally whereas I get to know the value of n in the main function.

Upvotes: 3

Views: 1589

Answers (2)

גלעד ברקן
גלעד ברקן

Reputation: 23955

Dynamic programming would be quite straightforward here. We have two choices: Choose from A or skip, Choose from B or skip. Our bottom-up recurrence could look like:

// Choose from A or skip
m[i][0] = max(A[i] + m[i - 1][1], m[i - 1][0])
// Choose from B or skip
m[i][1] = max(B[i] + m[i - 1][0], m[i - 1][1])

JavaScript code:

function f(A, B){
  let m = new Array(A.length + 1)

  for (let i=0; i<=A.length; i++)
    // [a or skip, b or skip]
    m[i] = [0, 0]

  for (let i=1; i<=A.length; i++){
    // Choose from A or skip
    m[i][0] = Math.max(
      A[i-1] + m[i - 1][1], m[i - 1][0])
    // Choose from B or skip
    m[i][1] = Math.max(
      B[i-1] + m[i - 1][0], m[i - 1][1])
  }

  return Math.max(...m[A.length])
}

var a = [9, 3, 5, 7, 3]
var b = [5, 8, 1, 4, 5]

console.log(f(a, b))

Upvotes: 3

Gene
Gene

Reputation: 47020

We can define 2 functions A and B. A(i) is the maximum height we can get by next choosing player with index i or greater from the first row. B(i) is the same for the second row. Now we can write A in terms of B and B in terms of A. For example A(i) is the max over all indices k that are i or greater by choosing the k'th element from the first set plus the max we can get by choosing from k+1 or higher from the second. B(i) is symmetric:

A(i) = max_{k=i..n} a[k] + B(k + 1); A(n) = a[n]
B(i) = max_{k=i..n} b[k] + A(k + 1); B(n) = b[n]    

The answer will be max(A(1), B(1)).

A simple way to go is just code this as it's written with 2 memoized functions. I'll use C rather than C++ with tweaking to use 0-based indices.

#include <stdio.h>

#define N 5
int a[] = {9, 3, 5, 7, 3};
int b[] = {5, 8, 1, 4, 5};
int Avals[N], Bvals[N];

int B(int i);

int A(int i) {
  if (i >= N) return 0;
  if (Avals[i]) return Avals[i];
  int max = 0;
  for (int k = i; k < N; ++k) {
    int val = a[k] + B(k + 1);
    if (val > max) max = val;
  }
  return Avals[i] = max;
}

int B(int i) {
  if (i >= N) return 0;
  if (Bvals[i]) return Bvals[i]; 
  int max = 0;
  for (int k = i; k < N; ++k) {
    int val = b[k] + A(k + 1);
    if (val > max) max = val;
  }
  return Bvals[i] = max;
}

int main(void) {
  int aMax = A(0);
  int bMax = B(0);
  printf("%d\n", aMax > bMax ? aMax : bMax);
  return 0;
}

I claim there's a way to replace the memoized recursion with simple loops that access the elements of Avals and Bvals in strictly decreasing index order, but I'll let you figure out the details. This result will be smaller, faster code.

Upvotes: 1

Related Questions