假设有一个数组A,里面的元素都大于1的正整数,只采用加号或乘号,不改变数组元素的位置,如何使最后结果最大?比如:
A={2,1,1,1,1,2}那么就用加号结果为8,B={3,1,3}那么就用乘号结果为9。
一开始我想从决策入手,即对每个位置逐次加上+或者*,然后利用回溯方面的思想或者动态规划来做,可是发现一旦遇到*,或者连续*,问题显得很复杂,无法实施。
这个题的特点就是发现特有的性质。 从+断开的地方左右是没有联系的,所以我们应该来安排+号,实现问题的分割。
我们从序列的头开始先找第一个加号,然后计算+左边的乘积,然后计算+右边的最大值。 右边也是同样的问题。
从各种加号的位置分布情况中找到一个最有的值。
- #include <iostream>
- using namespace std;
- #define MIN -1
- class Sum
- {
- private:
- int *result;//动态规划表格,result[n]表示1....n做加乘综合运算后的最大值
- int *path;//在动态规划递推过程中记录加号出现位置
- int *arr;//存放num个数字
- int num;//数字序列的长度
- public:
- //构造函数
- Sum(int num)//num个数字
- {
- this->num=num;
- result=new int[num+1];//用数组下标的1到n
- path=new int[num+1];//记录路径也只用1到n
- arr=new int[num+1];//开辟数组存放数字序列,只用1到n
- }
- //输入数字序列
- void input()
- {
- for(int i=1;i<=num;i++)
- {
- cin>>arr[i];
- }
- }
- //动态规划求解 ,公式: result[n]=max { (x[k]*x[k+1]*x[k+2]*....x[n])+result[k-1] } ,k取1....n
- void maxResult()
- {
- //初始化reslut[0]=0,即0个数据的最大值为0,初始化result[1]=arr[1],即前1个数据的最大值为本身
- result[0]=0;
- result[1]=arr[1];
- path[1]=1;
- //递推求解,最终result[n]表示前n个数的最大值
- int localSum;
- int temp;
- for(int i=2;i<=num;i++)
- {
- result[i]=MIN;
- localSum=1;
- for(int k=i;k>=1;k--)
- {
- //求x[k]*x[k+1]*.....x[i]
- localSum*=arr[k];
- //求x[k]*x[k+1]*.....x[i]+result[k-1]
- temp=localSum+result[k-1];
- //记录k取不同值时所能达到的最大值,并记录断点path[i]
- if(temp>result[i])
- {
- result[i]=temp;
- path[i]=k;
- }
- }
- }
- }
- //打印结果
- void display()
- {
- cout<<"最大*,+结果:"<<result[num]<<endl;
- printPath(num);
- }
- //递归打印整个公式
- void printPath(int n)
- {
- if(path[n]==1)
- {
- int j=1;
- while(j<=n)
- {
- cout<<arr[j];
- if(j<n)
- {
- cout<<"*";
- }
- ++j;
- }
- return;
- }
- printPath(path[n]-1);
- cout<<"+";
- int i=path[n];
- while(i<=n)
- {
- cout<<arr[i];
- if(i<n)
- {
- cout<<"*";
- }
- ++i;
- }
- }
- };
- void main()
- {
- Sum sum(6); // 2 1 1 1 1 2
- sum.input();
- sum.maxResult();
- sum.display();
- }
思想是动态规划求解 ,
公式: result[n]=max { (x[k]*x[k+1]*x[k+2]*....x[n])+result[k-1] } ,k取1....n
result[n]表示1...n的最大值
参考的 zyl072 的思路 ,重点理解 X*X*X + X*X*X*X + X + X*X
我们可以从2 1 1 1 1 2的最后往前找,找到一个位置放置一个加号,从这里断开,+ 的右边的是乘积运算 ,右边的乘积+左边的最大值就是整个序列最大值。 左边最大值是同样的子问题 ,会发现有最优子结构性质,动态规划递推就可以了。
关键就是单独的一个X也符合这个公式, 例如2 1 1 1 1 2, 我们可以把加号放在任何一个空位,然后对+右边做乘,对+左边继续递归计算。 例如 2 1 1 1 1 + 2, 这种情况是只有2自己做乘法运算,+左边是同样问题 2 1 1 1 1 ,且与父问题无关 ,这时候举个例子 2 + 1 1 1 1,右边4个1相乘,然后对2递归,2只有自己相乘了就是它本身2 ,公式就变成了 2+1*1*1*1+2 。 现在去看看公式就明白最优子结构了。