问题描述:
给出
N
N
N 个
1
1
1 -
9
9
9 的数字
(
v
1
,
v
2
,
…
,
v
N
)
(v1,v2,…,vN)
(v1,v2,…,vN),不改变它们的相对位置,在中间加入
K
K
K 个乘号和
N
−
K
−
1
N-K-1
N−K−1 个加号,括号随便加,使最终结果最大。因为乘号和加号一共就是
N
−
1
N-1
N−1 个,所以恰好每两个相邻数字之间都有一个符号。
例如:
N
=
5
N=5
N=5,
K
=
2
K=2
K=2,
5
5
5 个数字分别为
1
1
1、
2
2
2、
3
3
3、
4
4
4、
5
5
5,可以进行如下运算:
1
∗
2
∗
(
3
+
4
+
5
)
=
24
1*2*(3+4+5)=24
1∗2∗(3+4+5)=24
1
∗
(
2
+
3
)
∗
(
4
+
5
)
=
45
1*(2+3)*(4+5)=45
1∗(2+3)∗(4+5)=45
(
1
∗
2
+
3
)
∗
(
4
+
5
)
=
45
(1*2+3)*(4+5)=45
(1∗2+3)∗(4+5)=45
等等.
思路:
例如在计算
N
=
5
N=5
N=5,
K
=
2
K=2
K=2 时,我们可以通过计算
m
a
x
[
0
]
[
0
]
∗
(
2
+
3
+
4
+
5
)
max[0][0]*(2+3+4+5)
max[0][0]∗(2+3+4+5)、
m
a
x
[
0
]
[
1
]
∗
(
3
+
4
+
5
)
max[0][1]*(3+4+5)
max[0][1]∗(3+4+5)、
m
a
x
[
0
]
[
2
]
∗
(
4
+
5
)
max[0][2]*(4+5)
max[0][2]∗(4+5)、
m
a
x
[
0
]
[
3
]
∗
(
5
)
max[0][3]*(5)
max[0][3]∗(5)等等这些式子的最大值得到最终的结果,这样就建立起了动态规划的思路。
状态转移方程已经体现在代码之中了。
源代码:
//
// main.cpp
// InsertMultiplier
//
// Created by 胡昱 on 2022/1/5.
//
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
// 数字数量及其最大值
int n;
const int MAX_N = 20;
// 乘号数量及其最大值
int k;
const int MAX_K = MAX_N - 1;
// 存储数字数组
int digits[MAX_N];
// 动态规划数组,dp[i][j]表示从第0个数字到第i个数字中插入j个乘号时所得到的最大值
long long dp[MAX_N][MAX_N];
// 累加数组,sum[i][j]代表了从第i个数字到第j个数字累加的结果
long long sum[MAX_N][MAX_N];
int main(int argc, const char * argv[]) {
// 共M组测试用例
int M;
cin >> M;
while((M--) > 0) {
// 初始化(其实感觉不用初始化也可以)
memset(digits, 0, sizeof(digits));
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
// 输入数字数量n和乘号个数k
cin >> n >> k;
// 输入数字
for(int ni = 0; ni < n; ++ni) {
cin >> digits[ni];
}
// 初始化累加数组
for(int ni = 0; ni < n; ++ni) {
long long temp = 0;
for(int nj = ni; nj < n; ++nj) {
temp += digits[nj];
sum[ni][nj] = temp;
}
}
// 初始化动态规划数组(插入乘号数量为0时就等于一直累加)
for(int ni = 0; ni < n; ++ni) {
dp[ni][0] = sum[0][ni];
}
// 开始动态规划
// 递推式挺好理解的,也就是取后面累加的值和前面某一段的最大值的乘积的最大值
for(int ni = 0; ni < n; ++ni) {
// 插入的乘号数量不仅要小于等于k,还要小于当前数字数量
for(int ki = 1; ki <= k && ki <= ni; ++ki) {
for(int nj = 0; nj < ni; ++nj) {
dp[ni][ki] = max(dp[nj][ki - 1] * sum[nj + 1][ni], dp[ni][ki]);
}
}
}
// 输出结果
cout << dp[n - 1][k] << endl;
}
return 0;
}