题目:给出N个1-9的数字 (v1,v2,…,vN),不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大。因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号。并说明其具有优化子结构性质及子问题重叠性质。(20分)
例如: 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
S(T,start,len)表示在T序列中 从start位置开始 len个元素的和
F(T,start,len,num)表示在序列T中,从start位置开始 len个长度的的元素中插入num个乘号的最大值
F(T,start,len,num) = max{ S(T,start,leftlen) * F(T, leftlen,len-leftlen, mulcount-1) }
最优子结构性质: F(T,start,len,num) = max{ S(T,start,leftlen) * F(T, leftlen,len-leftlen, mulcount-1) } 假设F(T, leftlen,len-leftlen, mulcount-1) 不是最大的 则存在
F’ (T, leftlen,len-leftlen, mulcount-1)> F(T, leftlen,len-leftlen, mulcount-1)
S(T,start,leftlen) * F’(T, leftlen,len-leftlen, mulcount-1)> S(T,start,leftlen) * F(T, leftlen,len-leftlen, mulcount-1)
则存在F’(T,start,len,num)> F(T,start,len,num) 则 F(T,start,len,num)不是最大的 与条件矛盾 所以F(T, leftlen,len-leftlen, mulcount-1)是最大的 所以具有最优子结构的性质
F(T,1,5,2)
F(T,2 ,5,1) F(T,3,5,1) F(T,4,5,1)
F(T,3,5,0) F(T,4,5,0) F(T,5,5,0)
所以具有子问题的重叠性
// maxnum.cpp : Defines the entry point for the console application.
//
//F(start,len,multinum) 代表从start位置开始 len个元素长度 有multinum个乘号的的最大值
//S(start,len)代表从start位置开始len个元素的和
//F(start,len,multinum)=max{S(start,leftlen)*F(start+leftlen,len-leftlen,multinum-1) 1<=leftlen<=len
// 如果len-1<multinum 则F(start,len,multinum)=0
//如果multinum=0 则F(start ,len,multinum)=S(start,len)
#include "stdafx.h"
// maxnum.cpp : Defines the entry point for the console application.
//
//F(start,end,multinum) 代表从start位置开始到end位置结束 有multinum个乘号的的最大值
//S(start,end)代表从start位置开始到end位置结束的和
//F(start,end,multinum)=max{S(start,middle)*F(middle+1,end,multinum-1) start=<middle<=end;
//如果multinum=0 则F(start ,end,multinum)=S(start,end)
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
class SeekMax
{
public:
SeekMax(int num );
SeekMax(SeekMax&s);//copy constructor
~SeekMax();
int Seek();//Seek the max multiplication number
private:
vector <int> list;
int multinum;
int S(int start, int end);
int F(int start, int end, int m);
};
SeekMax::SeekMax(int num )
{
multinum = num;
int temp;
while (1)
{
cin >> temp;
if (temp == -1)break;
list.push_back(temp);
}
}
SeekMax::SeekMax(SeekMax&s)
{
multinum = s.multinum;
list.clear();
for (auto a = s.list.begin(); a != s.list.end(); a++)
list.push_back(*a);
}
SeekMax::~SeekMax()
{
list.clear();
}
int SeekMax::Seek()
{
return F(0, list.size()-1, multinum);
}
int SeekMax::S(int start, int end)
{
int sum = 0;
for (int i = start; i <=end; i++)
{
sum += list[i];
}
return sum;
}
int SeekMax::F(int start, int end, int m)
{
if (start >end)return 0;
if (end-start+1-1< m)return 0;//从下标start 开始到下标end 最多能放下end-start+1-1个乘法符号
int middle, temp, max;
if (m == 0)//没有乘号的话直接计算加法的总值
return S(start, end);
max = 0;
for ( middle= start; middle<=end; middle++)
{
temp = S(start,middle)*F(middle+1, end, m - 1);
if (temp > max)
max = temp;
}
return max;
}
int main(int argc, char **argv)
{
SeekMax myseek(2);
cout << "the max multiplication is " << myseek.Seek() << endl;
system("pause");
return 0;
}