数字序列加入+,*运算符后取得最大值问题; 动态规划;打破传统从决策入手思想;找出问题的特有性质;从例子入手找特点
2014-03-06 21:56
756 查看
假设有一个数组A,里面的元素都大于1的正整数,只采用加号或乘号,不改变数组元素的位置,如何使最后结果最大?比如:
A={2,1,1,1,1,2}那么就用加号结果为8,B={3,1,3}那么就用乘号结果为9。
一开始我想从决策入手,即对每个位置逐次加上+或者*,然后利用回溯方面的思想或者动态规划来做,可是发现一旦遇到*,或者连续*,问题显得很复杂,无法实施。
这个题的特点就是发现特有的性质。 从+断开的地方左右是没有联系的,所以我们应该来安排+号,实现问题的分割。
我们从序列的头开始先找第一个加号,然后计算+左边的乘积,然后计算+右边的最大值。 右边也是同样的问题。
从各种加号的位置分布情况中找到一个最有的值。
[cpp] view
plaincopy
#include <iostream>
using namespace std;
#define MIN -1
class Sum
{
private:
int *result;//动态规划表格,result
表示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
=max { (x[k]*x[k+1]*x[k+2]*....x
)+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个数的最大值
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
==1)
{
int j=1;
while(j<=n)
{
cout<<arr[j];
if(j<n)
{
cout<<"*";
}
++j;
}
return;
}
printPath(path
-1);
cout<<"+";
int i=path
;
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
=max { (x[k]*x[k+1]*x[k+2]*....x
)+result[k-1] } ,k取1....n
result
表示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 。 现在去看看公式就明白最优子结构了。
A={2,1,1,1,1,2}那么就用加号结果为8,B={3,1,3}那么就用乘号结果为9。
一开始我想从决策入手,即对每个位置逐次加上+或者*,然后利用回溯方面的思想或者动态规划来做,可是发现一旦遇到*,或者连续*,问题显得很复杂,无法实施。
这个题的特点就是发现特有的性质。 从+断开的地方左右是没有联系的,所以我们应该来安排+号,实现问题的分割。
我们从序列的头开始先找第一个加号,然后计算+左边的乘积,然后计算+右边的最大值。 右边也是同样的问题。
从各种加号的位置分布情况中找到一个最有的值。
[cpp] view
plaincopy
#include <iostream>
using namespace std;
#define MIN -1
class Sum
{
private:
int *result;//动态规划表格,result
表示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
=max { (x[k]*x[k+1]*x[k+2]*....x
)+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个数的最大值
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
==1)
{
int j=1;
while(j<=n)
{
cout<<arr[j];
if(j<n)
{
cout<<"*";
}
++j;
}
return;
}
printPath(path
-1);
cout<<"+";
int i=path
;
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
=max { (x[k]*x[k+1]*x[k+2]*....x
)+result[k-1] } ,k取1....n
result
表示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 。 现在去看看公式就明白最优子结构了。
相关文章推荐
- 数字序列加入+,*运算符后取得最大值问题; 动态规划;打破传统从决策入手思想;找出问题的特有性质;从例子入手找特点;
- hdu-1003-动态规划-求连续子序列最大和问题
- POJ 2479 动态规划 最大子序列问题(两段) Maximum sum
- n个数里面找出最大的m个数字(快排思想)
- 最大数字序列和问题,买卖股票问题,以及最长公共字串问题
- ACM-游玩景点(AC,动态规划,最大子序列和问题)
- 最大子序列和问题(动态规划)
- java 动态规划最大公共子序列问题
- (5)最大m段子序列和问题____动态规划
- 动态规划——最大子序列之和-数塔问题
- 输入一串字符,只包含“0-10”和“,”,找出其中最小的数字和最大的数字(可能不止一个),输出最后剩余数字个数
- 最大连续子序列和-动态规划
- 【动态规划】数字三角形最大值(一)(递归)
- 4clojure第56个问题从序列中找出不同的项并保持次序
- 动态规划5:求解最多航线问题(应用了最长子序列知识)
- JS+PHP实现用户输入数字后取得最大的值并显示为第几个
- 最大子序列求和问题
- 动态规划-最大子段和系列问题
- C++ 关于最大连续子序列(和最大)问题
- 一中OJ #1453 马棚问题 | 动态规划 序列分组DP | 解题报告