最大的算式(BigExp) 动态规划

还记得是去年做的DP题目,题目大意如下:

给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大。因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号。例如:

N=5, K=25个数字分别为12345,可以加成:

1*2*(3+4+5)=24

1*(2+3)*(4+5)=45

   。。。

输入

输入文件共有二行,第一行为两个有空格隔开的整数,表示NK,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在09之间)。

 

输出

输出文件仅一行包含一个整数,表示要求的最大的结果

 

样例

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[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;
  }	
}

给一组有很多0的数据:

15 5
0 1 0 0 1 0 1 0 1 1 1 0 1 1 0

答案是12 


如果用错误的枚举最后一次的方法 答案是3


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值