如何通过动态编程方法解决此问题?

时间:2019-07-26 19:15:28

标签: c++ algorithm recursion dynamic-programming

我正在解决数组的一个非常基本的问题。问题陈述如下:

SIS开设了一个篮球场,因此Demid决定举行一次篮球运动。 2⋅n名学生参加了Demid的练习,他将他们排成两排,每排大小相同(每排恰好有n个人)。学生按从左到右的顺序在每一行中从1到n编号。

现在Demid想选择一支球队打篮球。他将从左至右选择玩家,每个所选玩家的索引(不包括第一个被采纳的玩家)将严格大于先前选择的玩家的索引。为了避免偏爱某一行,Demid选择学生的方式是,没有连续选中的学生属于同一行。可以从所有2n名学生中选择第一个学生(没有其他限制),一个团队可以由任意数量的学生组成。

德米德(Demid)认为,为了组建一支完美的团队,他应该以这样一种方式选择学生,即所有被选学生的总身高是最大可能的。帮助Demid找到他可以选择的球队中最大的球员身高。

例如,如果输入为:(第一行包含n的值,接下来的第二行包含学生的身高)

5
9 3 5 7 3
5 8 1 4 5

我的方法是:

#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);
}

这是我基于逻辑推理的算法。我还没有编码,以后再编码。 请随时指出代码中的任何逻辑错误。

我知道可以使用动态编程方法轻松解决此问题,而该算法并非如此。 在这种情况下功能会如何?

据我所知,该算法的问题是我需要全局声明arr1arr2,而我却要知道主函数中n的值。

2 个答案:

答案 0 :(得分:2)

这里的动态编程非常简单。我们有两个选择:从A选择或跳过,从B选择或跳过。我们的自下而上的重复周期可能像这样:

// 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代码:

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))

答案 1 :(得分:1)

我们可以定义2个函数A和B。A(i)是我们接下来从第一行中选择索引i或更大的玩家可以获得的最大身高。 B(i)对于第二行是相同的。现在我们可以用B来表示A,用B来表示B。例如,A(i)是所有索引i为i或更大的k的最大值,方法是从第一个集合中选择第k个元素加上我们可以得到的最大值通过选择k + 1或更高的秒数来获得。 B(i)是对称的:

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]    

答案将是max(A(1),B(1))。

一个简单的方法就是编写代码,因为它带有2个记忆函数。我将使用C而不是C ++进行调整,以使用基于0的索引。

#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;
}

我声称有一种方法可以用简单的循环来代替已记录的递归,该循环以严格递减的索引顺序访问Avals和Bvals的元素,但我将让您弄清楚细节。结果将是更小,更快的代码。