1.问题描述
插入乘号 | ||
---|---|---|
Time Limit: 1000 MS | Memory Limit: 1000 KB |
Description
给出N个1-9的数字 (v1,v2,…,vN), 不改变它们的相对位置, 在中间加入K个乘号和N-K-1个加号, 括号随便加,
使最终结果最大。因为乘号和加号一共就是N-1个,所以恰好每两个相邻数字之间都有一个符号。
例如: N=5, K=2,5个数字分别为1、2、3、4、5,可以进行如下运算:
1*2*(3+4+5)=24
1*(2+3)*(4+5)=45
(1*2+3)*(4+5)=45
等等.
Input
第一行输入M(M<=10)表示有M组数据。每组数据输入两整数N和K(N<=20, K<20), 接下来输入N个1-9的数字。
Output
输出M行正整数,第i行表示第i组数据的最大结果, 你可能需要用long long类型存储结果。
Sample Input
2
5 2
1 2 3 4 5
6 3
1 2 3 4 5 6
Sample Output
120
720
2.思路分析:
- 首先,我们输入测试用例的数量 T。
- 对于每个测试用例,我们输入数组的长度 N 和可取的最大元素个数 K。
- 接下来,我们输入数组的元素,存储在 arr 数组中。
- 我们创建一个动态规划数组 dp,其中 dp[i][j] 表示前 i 个元素中选择 j 个元素进行乘积的最大值。
- 初始化动态规划数组的第一列 dp[i][0],表示前 i 个元素中不选择任何元素的乘积,即取前缀和。
- 对于每个 i(从 2 到 N),我们遍历可取的元素个数 j(从 1 到 min(K, i-1)):
- 对于每个 k(从 2 到 i),我们计算 dp[i][j] 的值,即选择 k 作为最后一个元素,将问题分解为两部分:
- 前 k-1 个元素中选择 j-1 个元素进行乘积,即 dp[k-1][j-1]。
- k 到 i 之间的元素的乘积,即 sum(arr, k, i)。
- 取上述两部分的乘积的最大值,更新 dp[i][j]。
- 对于每个 k(从 2 到 i),我们计算 dp[i][j] 的值,即选择 k 作为最后一个元素,将问题分解为两部分:
- 最后,输出 dp[N][K],即最大乘积和。
这段代码利用动态规划的思想,通过填充动态规划数组 dp 来计算最大乘积和。每个状态的计算依赖于前面已经计算的状态,通过递推得到最终结果。
3.代码示例
#include<iostream>
#include<cmath>
#include<limits.h>
const int MAX = INT_MAX;
using namespace std;
int sum(int a[], int s, int e)
{
int sum = 0;
for (int i = s; i <= e; i++)
sum += a[i];
return sum;
}
int main()
{
int T;
cin >> T;
while (T--)
{
long long dp[21][21] = { 0 };
int arr[21];
int N, K;
cin >> N >> K;
for (int i = 1; i <= N; i++)
{
cin >> arr[i];
}
for (int i = 1; i <= N; i++)
dp[i][0] = sum(arr, 1, i);
for (int i = 2; i <= N; i++) {
for (int j = 1; j <= min(K,i-1); j++){
for (int k = 2; k <= i; k++)
{
dp[i][j] = max((dp[k-1][j-1] * (sum(arr,k,i))),dp[i][j]);
}
}
}
cout << dp[N][K] << endl;
}
return 0;
}