问题
设I是一个n位十进制整数。如果将I划分为k段,则可得到k个整数。这k个整数的乘积称为I的一个k乘积。试设计一个算法,对于给定的I和k,求出I的最大k乘积。
编程任务:
对于给定的I 和k,编程计算I 的最大k 乘积。
需求输入:
输入的第1 行中有2个正整数n和k。正整数n是序列的长度;正整数k是分割的段数。接下来的一行中是一个n位十进制整数。(n<=10)
需求输出:
计算出的最大k乘积。
例如输入
4 3
1234
输出:144
分析
设m(i,j)表示将第i~n位数划分为j段的最大乘积
设n位的整数用字符串表示为X1X2X3...Xn
假设n为5,整数为12345
则m(1,3)就表示为从第一位到第五位划分为三个整数
例如可以这样分:{1*23*45} {1*2*345} {1*234*5} {12*3*45} {12*34*5} {123*4*5}
其中最大的就是123*4*5=2460
a(i,j)表示将第i位到第j位化成一个整体,例如a(2,3)=23
m(i,j) = max{ a(i,s)*m(i+s,j-1) } 1 <= j <= n-i+1 1 <= s <= (n-i+1)-(j-1)
上面式子表示m(i,j)可以将前面i~i+s-1位看成一个整体,后面i+s~j再划分位j-1个整数 s就是中间的切分点
其中边界值位:m(i,1) = a(i,n);即把i~n看成一个整体
代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//截取子字符串
void SubStr(char *s,int start,int end,char *newStr){
int i,j;
for(i = start-1,j = 0; i <= end-1; i++){
newStr[j++] = s[i];
}
newStr[end-start+1] = '\0';
}
//将字符串转换为整数
int ConvertInt(char *s,int start,int end){
SubStr(s,start,end,newStr);
int a = atoi(newStr);
return a;
}
void solve(int n,int k,char *num){
//初始化
int m[n+1][n+1];
for(int i = 1; i <= n; i++){
m[i][1] = ConvertInt(num,i,n);
for(int j = 2; j <= n; j++)
m[i][j] = 0;
}
//自顶向下递归的计算
for(int i = n-1; i >= 1; i--){
for(int j = 2; j <= n-i+1; j++){
for(int s = 1; s <= (n-i+1)-(j-1); s++){
int a = ConvertInt(num,i,i+s-1);//a(i,i+s-1);
int b = m[i+s][j-1];
int c = a * b;
if(c > m[i][j])
m[i][j] = c;
}
}
}
printf("最大%d乘积为:%d",k,m[1][k]);
}
int main(){
int n,k;
scanf("%d %d",&n,&k);
if(n > 10 || k > n) return 0;
char num[n+1];
int i = 0;
getchar();//吸收回车
do{
num[i] = getchar();
++i;
}while(i < n);
solve(n,k,num);
return 0;
}