最大的算式(BigExp) 动态规划
2015-11-25 18:41
246 查看
还记得是去年做的DP题目,题目大意如下:
给出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
。。。
输入
输入文件共有二行,第一行为两个有空格隔开的整数,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在0到9之间)。
输出
输出文件仅一行包含一个整数,表示要求的最大的结果
样例
BIGEXP.IN
5 2
1 2 3 4 5
BIGEXP.OUT
120 // (1+2+3)*4*5=120
当时记得很清楚,老师给出的转移方程是:
F[i][j]表示前i个数字用j个乘号所有的最大值;
F[i][j]=max{F[i-1][j]+arr[i],[F[i-k][j-1]*sum[i-k+1][i]};
当时就是得了90分(据说在各大oj上能AC)
然后班里的大犇说:方程不对,要三维的区间DP。
去年的我实在太弱了,不提了,这几天突然想起来,没思考多久,代码就想出来了。
题目不能枚举最后一次乘法,这是不对的,遇到多的‘0’就要傻眼了,应该采用分治思想,把一段区间内一分为二,这样能保证得到的答案最大。
给一组有很多0的数据:
15 5
0 1 0 0 1 0 1 0 1 1 1 0 1 1 0
答案是12
如果用错误的枚举最后一次的方法 答案是3
给出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
。。。
输入
输入文件共有二行,第一行为两个有空格隔开的整数,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在0到9之间)。
输出
输出文件仅一行包含一个整数,表示要求的最大的结果
样例
BIGEXP.IN
5 2
1 2 3 4 5
BIGEXP.OUT
120 // (1+2+3)*4*5=120
当时记得很清楚,老师给出的转移方程是:
F[i][j]表示前i个数字用j个乘号所有的最大值;
F[i][j]=max{F[i-1][j]+arr[i],[F[i-k][j-1]*sum[i-k+1][i]};
当时就是得了90分(据说在各大oj上能AC)
然后班里的大犇说:方程不对,要三维的区间DP。
去年的我实在太弱了,不提了,这几天突然想起来,没思考多久,代码就想出来了。
题目不能枚举最后一次乘法,这是不对的,遇到多的‘0’就要傻眼了,应该采用分治思想,把一段区间内一分为二,这样能保证得到的答案最大。
#include <iostream> #include <cstring> #define N 20 #define m_inf -999999 using namespace std; int f ; //dp三维数组 int sum ; //求i~j的总和 int arr ; //保存数字 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; } }
给一组有很多0的数据:
15 5
0 1 0 0 1 0 1 0 1 1 1 0 1 1 0
答案是12
如果用错误的枚举最后一次的方法 答案是3
相关文章推荐
- GET/POST两种方式的比较及延伸
- SVN and GitHub
- SpringMVC
- 漫谈iOS Crash收集框架
- 设置 ListBox 选中项的背景颜色
- 转:Ubuntu源码编译vim/gvim7.4
- 南大软院大神养成计划--js
- java hdu2085 水水水水水水水水水水水水水水
- hdu 1002
- 360浏览器 与 IE的兼容性模式笔记
- Item 9: 比起typedef更偏爱别名声明(alias declaration)
- POJ - 2516 Minimum Cost(最小费用最大流)
- 使用GridView的auto_fit遇到的坑
- 十分钟搞清字符集和字符编码
- Java Web(8)struts2 result 返回json,jQuery 解析显示
- SSH Secure File Transfer Client传送文件
- Linux C 正则表达式运用(regex.h)
- gradle工程导入eclipse---下载安装CAS证书
- Android帧动画三步骤
- windows客户端安装