如何通过动态规划方法解决这个问题?

How to solve this problem through dynamic programming approach?

本文关键字:问题 解决 何通过 动态规划 方法      更新时间:2023-10-16

我正在解决数组上一个非常基本的问题。问题陈述是这样的:

SIS已经开设了一个篮球场,所以Demid决定举行一次篮球锻炼会。 2⋅n学生来到Demid的锻炼课程,他将他们排成两排相同大小的排(每排正好有n个人)。学生在每行中按从左到右的顺序从 1 到 n 编号。

现在德米德想选择一支球队打篮球。他会从左到右选择球员,每个被选中的球员的指数(不包括第一个被抽取的)将严格大于之前选择的球员的指数。为了避免优先选择其中一行,Demid 选择学生的方式是没有连续选择的学生属于同一行。第一个学生可以在所有2n名学生中选择(没有额外的限制),一个团队可以由任意数量的学生组成。

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

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

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,而我知道 main 函数中 n 的值。

动态编程在这里非常简单。我们有两个选择:从 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))

我们可以定义 2 个函数 A 和 B。A(i) 是我们接下来从第一行选择索引为 i 或更大的球员可以获得的最大高度。 B(i) 与第二行相同。现在我们可以用 B 写 A,用 A 写 B。例如,A(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("%dn", aMax > bMax ? aMax : bMax);
return 0;
}

我声称有一种方法可以用简单的循环替换记忆递归,这些循环以严格的索引顺序访问 Avals 和 Bvals 的元素,但我会让你弄清楚细节。这个结果将是更小、更快的代码。