问题: 最大的算式
题目描述
题目很简单,给出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之间)。
输出
输出文件仅一行包含一个整数,表示要求的最大的结果
最后的结果<=maxlongint
样例
#1
输入
5 2
1 2 3 4 5
输出
120
以前的思路
认为f[i][j][k]应该是这样定义的:
设f[i][j][k]为在[i , j] 的区间内有k个乘号
状态转移方程:
f[i][j][k] = max4(f[i+1][j][k]+a[i],f[i][j-1][k]+a[j],
f[i+1][j][k-1]*a[i],f[i][j-1][k-1]*a[j]);
那么错代码就应该是这样:
#include<bits/stdc++.h>
using namespace std;
const int N = 101;
int n,m,a[N],f[N][N][N*11];
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> a[i];
for(int i=n;i>0;i--){
for(int j=i;j<=n;j++){
for(int k=0;k<=m;k++){
f[i][j][k] = max(f[i+1][j][k]+a[i],
max(f[i+1][j][k-1]*a[i],
max(f[i][j-1][k]+a[j],
f[i][j-1][k-1]*a[j])));
}
}
}
cout << f[1][n][m] << endl;
}
/**************************************************************
Language: C++
Result: 答案错误50
****************************************************************/
得了50分,后来又找到那几个错误样例一对比发现:
这个区间不止可以从两边切开,还能从中间的任意位置切开,如果将中间线进行循环,那么乘号的个数也是可以多可以少的。这时f[i][j][k]的初始化就要变为-INF这样在运行max函数的时候才能找到最优方案
上AC代码:
#include<bits/stdc++.h>
#define INF 2147483647
using namespace std;
const int N = 110;
int n,m,a[N],f[N][N][N];
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++){cin >> a[i];}
for(int i=1;i<=n;i++){
f[i][i][0] = a[i];
}
for(int i=n;i>0;i--){
for(int j=i+1;j<=n;j++){
for(int k=0;k<=min(j-i,m);k++){
if(m-(n-(j-i))>=k){
f[i][j][k]=-INF;
continue;
}
for(int z=i;z<j;z++){
for(int y=0;y<=k;y++){
f[i][j][k] = max(f[i][j][k],f[i][z][y]+f[z+1][j][k-y]);
if(y==0){
f[i][j][k] = max(f[i][z][y]*f[z+1][j][k-y-1],
f[i][j][k]);
}
else{
f[i][j][k] = max(f[i][z][y-1]*f[z+1][j][k-y],
f[i][j][k]);
}
}
}
}
}
}
// cout << f[3][5][1] <<endl;
cout << f[1][n][m] << endl;
}
/**************************************************************
Language: C++
Result: 正确100
Time:0 ms
Memory:6912 kb
****************************************************************/