题目描述
题目很简单,给出N个数字,不改变它们的相对位置,在中间加入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
……
输入
共有二行,第一行为两个有空格隔开的整数,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在0到9之间)。
输出
仅一行包含一个整数,表示要求的最大的结果
样例输入
5 2 1 2 3 4 5
提示
说明
(1+2+3)*4*5=120
分析:典型的动态规划问题嘛。加号就是用来唬人的,因为加号和乘号总个数是N-1,可以保证每两个数中间都一定有一个运算符,所以只考虑乘号就可以了。用f[i][j]表示在前i个数中插入j个乘号所能达到的最大运算和,可以得到状态转移方程f[i][j]=max(f[i][j],f[i-l][j-1]*(sum[i]-sum[l-1]),其中2<=l<=i,sum数组记录的是前i个数的总和。初始值f[i][0]=sum[i],1<=i<=n。
#include<iostream>
using namespace std;
int n,k;
long long f[120][120],sum[120];
int main()
{
scanf("%d%d",&n,&k);
int t;
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
sum[i]=sum[i-1]+t;
}
for(int i=1;i<=n;i++)f[i][0]=sum[i];
for(int i=2;i<=n;i++)
{
t=min(i-1,k);
for(int j=1;j<=t;j++)
for(int l=2;l<=i;l++)f[i][j]=max(f[i][j],f[l-1][j-1]*(sum[i]-sum[l-1]));
}
printf("%lld\n",f[n][k]);
return 0;
}
另外一种有点小区别,在关于l取值的时候,上述的范围在2<=l<=i, 下述的范围在2<=l<=n.但是最后运行的结果都是相同的。
#include <iostream>
using namespace std;
#define max(a, b) a > b ? a : b;
long long int dp[16][16];
int sum[16];
int main() {
int n, k;
cin >> n >> k;
for(int i = 1; i <= n; i++) {
int temp;
cin >> temp;
sum[i] = sum[i-1] + temp;
}
for(int i = 1; i <= n; i++) {
dp[i][0] = sum[i];
}
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= i-1 && j <= k; j++) {
for(int l = 2; l <= n; l++) {
dp[i][j] = max(dp[i][j], dp[l-1][j-1] * (sum[i] - sum[l-1]));
}
}
}
cout << dp[n][k];
return 0;
}
第三种方法如下,还不太懂。
第三种 提供了另外的一种思路
#include <iostream>
#include <cstring>
#define N 20
#define m_inf -999999
using namespace std;
int f[N][N][N]; //dp三维数组
int sum[N][N]; //求i~j的总和
int arr[N]; //保存数字
int n,m;
void reset() //清空数组
{
memset(f,0,sizeof(f));
memset(arr,0,sizeof(arr));
memset(sum,0,sizeof(sum));
}
int search(int s,int e,int k) //记忆化搜索
{
if(e-s<k)return f[s][e][k]=m_inf; //如果长度小于乘号个数,返回负无穷
if(f[s][e][k]!=0)return f[s][e][k];
int &maxnum=f[s][e][k];
if(k==0)maxnum=sum[s][e]; //乘号个数为0时即为求和
else
for (int i=s;i<e;++i) //枚举中间点
{
for(int j=0;j<=k;++j)
maxnum=max(maxnum,search(s,i,j)+search(i+1,e,k-j)); //如果左右相加
for(int j=0;j<k;++j)
maxnum=max(maxnum,search(s,i,j)*search(i+1,e,k-j-1));//如果左右相乘
}
return maxnum;
}
int main()
{
while(cin>>n>>m)
{
reset();
for (int i=1;i<=n;++i)
cin>>arr[i];
for (int i=1;i<=n;++i)
for (int j=i;j<=n;++j)
sum[i][j]+=sum[i][j-1]+arr[j];
cout<<search(1,n,m)<<endl;
}
}