问题描述:
设有一个长度为N 的数字串,要求选手使用K 个乘号将它分成K+1 个部分,找出一种分法,使得这K+1 个部分的乘积最大。
同时,为了帮助选手能够理解题意,主持人还举了如下一个例子:
有一个数字串:312 ,当N=3 ,K=1 时会有两种分法:
⑴3*12=36
⑵31*2=62
这时,符合题目要求的结果是:31*2=62 。现在,请你帮助你的好朋友XZ 设计一个程序,求得正确的答案。
输入
程序的输入共有两行:
第一行共有2 个自然数N ,K (2 ≤N ≤40 ,1 ≤K ≤6 )
第二行是一个长度为N 的数字串。
输出
结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。
样例输入
4 2
1231
样例输出
62
问题分析:
由于自然数位数的上限为40 ,乘号数的上限为6 ,因此最大乘积位数的上限接近42 位。显然,运算任何整数类型都无法容纳如此之大的数据,这里介绍动态规划的解法。 动态规划求解 对于长度为n的字符序列。对于字符序列s1,s2,……,si,(0=<i<n),插入j个“*”后形成最大乘积,用c[i][j]表示。 假设第j个“*”的插入位置是sk(之后),那么可以证明,对于s1,s2,……,sk,(0<=k<i),插入j-1个“*”也形成一个最大乘积c[k][j-1]。 于是我们就找到了这个问题的最优子结构:
其中,要保证j>=0,并且j<=K && j<i+1(即对于元素(s0~s(i)),最多插入i个“*”)。
对于边界情况,即当j=0时,c[i][0]=s[s0,……,s(i-1)]表示的整数值,(0=<i<n)。
建立数组c[N][K+1],因为j可以达到K,所以第二维长度应该为K+1。
实现代码如下:
1 #include <iostream>
2 using namespace std;
3
4 #define N 4 //the len of array
5 #define M 2 //the count of *
6 int countArray(char *s,int start,int len)
7 {
8 long sum = 0;
9 for(int i = 0;i<len;i++)
10 {
11 sum = sum*10 + s[start+i]-48;
12 }
13 return sum;
14 }
15 void max_multipl(int c[][M+1],char *s)
16 {
17 int i = 0;
18 int j = 0;
19 for(i = 0;i<N;i++)
20 {
21 c[i][0] = countArray(s,0,i+1);
22 cout << c[i][0]<< endl;
23 }
24 for(i = 0;i<N;i++)//数组元素从0开始
25 {
26 for(j = 1;j< i+1 && j<= M;j++)
27 {
28 c[i][j] = 0;
29 for(int k = 0;k<i;k++)
30 {
31 long t;
32 t = c[k][j-1] * countArray(s,k+1,i-k);
33 cout <<"***************" << endl;
34 cout << c[k][j-1] << " " <<t << endl;
35 if(t>c[i][j])
36 c[i][j] = t;
37 cout << "c["<<i<<"]"<<"["<<j<<"] = "<<c[i][j]<<endl;
38 cout <<"***************" << endl;
39 }
40 }
41
42 }
43 //cout << c[N-1][M];
44 }
45 int main()
46 {
47 char s[N] = {'1','2','3','5'};
48 int c[N][M+1]={0};
49 max_multipl(c,s);
50 }
该博客介绍了如何使用动态规划解决寻找数字串中插入K个乘号以获得最大乘积的问题。通过分析问题的最优子结构,建立二维数组c[N][K+1]进行求解,提供了一个C语言实现的代码示例。
5546

被折叠的 条评论
为什么被折叠?



