1.题目
设I 是一个n 位十进制整数。如果将I 划分为k 段,则可得到k 个整数。这k 个整数的乘积称为I 的一个k 乘积。对于给定的I 、n和k,试设计一个算法,编程计算I 的最大k 乘积。
输入:
3(k值)
456(目标数字l的字符串)
输出:
270(I分成k组的最大乘积)
2.思路
1) 子问题划分
(1)将划分成k组的问题想象成在划分成k-1组的基础上再多划分一组,即 将l分成k组 = 将l分成k-1组 + 剩余的一组(此一组可为l中任意值),由于要使l划分成k组的乘积最大,故将l分成k-1组时的乘积也要最大。因此确定了备忘录中的一维i为划分的组数,i=1,2,..,k;
(2)由于要将数字l进行不同的划分,故我们需要将l拆分不为不同的子字符串,因此其备忘录中的另一维j应为l字符串中的字符个数,j=1,2,...,n;
设m[i,j]为l中前j个字符划分为i组时的最大乘积
2)递推公式
(1)初值:m[i,j] = 0 i<j
m[1,j] = numStr.subString (0,j);//此处的numStr即l的字符串形式
(2)递推式:m[i,j] = min{m[i-1,k] * (int)numStr.subString(k,j)}
i-1<=k<j
参数k为遍历上一分组i-1时的游标,旨在遍历所有前j-1个字符下的m-1组的最大乘积.
3.代码
public class DP_最大k乘积问题 {
static int k,
n;
static String numStr;
static int maxMultipleOfK(){
int[][] m = new int[k+1][n+1];
int[] sum = new int[n+1];
for(int i=1;i<=n;i++){
m[1][i] = Integer.parseInt(numStr.substring(0,i));
}
for(int i=2;i<=k;i++){
for(int j=i;j<=n;j++){
for(int k=i-1;k<j;k++){
int q = m[i-1][k] * Integer.parseInt(numStr.substring(k,j));
if(q > m[i][j])
m[i][j] = q;
}
}
}
return m[k][n];
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
k = Integer.parseInt(br.readLine());
numStr = br.readLine();
n = numStr.length();
System.out.println(maxMultipleOfK());
}
}