最大K乘积的问题:
在一个长度为N的数字串中插入K-1个乘号,将N分成K部分,找出一种分法,使得这K个部分的最大乘积最大。
例如有一个数字串:312,当N=3,K=2时会有以下几种分法:
3*12=36 31*2=62
但是符合题目的是31*2=62,通过这个例子很明显的可以看出最大k乘积的问题,就是求一个数,将其分成k段,求出段相乘的最大值问题。
要求解此问题要用到动态规划的思想,在这里要用到两个数据来分别表示不同的含义
w(h1,h2)表示第h1位到第h2位所组成的十进制数(h2.>h1)
m(i,j)表示:前i位(从1.......N)分成j段所得的最大乘积,则可得到如下的DP方程
if(j==1) m(i,1)=w(1,i);
if(j>=1&&j<k)
m(i,j)=max{ m(d,j-1)*w(d+1,i)(1<d<i) }
else if(i<j) m(i,j)=0;
这是一个动态规划的式子。
这里是java实现的主要代码:
/** * 对得到的数组进行处理,得到最大K乘积 */ private void maxValue() { int size = num.length; /** * 先把value[i][j]初始化,其代表的是从i开始到j所代表的的整数i<j */ for (int i = 0; i < size; i++) { value[i][i] = num[i]; for (int j = i + 1; j < size; j++) { value[i][j] = value[i][j - 1] * 10 + num[j]; } } /** * 初始化maxValue第一列,即前i+1位,分成1段所得的最大乘积 * 初始化bit第一行和第一列,即当前i+1位分成1段时最后一个乘号的位置,和第一位分成i+1段时最后一个乘号出现的位置,都将他们的初始化为零 */ for (int i = 0; i < size; i++) { maxValue[i][0] = value[0][i]; bit[0][i] = 0; bit[i][0] = 0; } // 关键代码得maxValue[i][j]的值,即前i+1位分成j+1段时的最大乘积(因为下表从零开始) for (int i = 1; i < size; i++) { //分成二段到intDuan段 for (int j = 1; j < intDuan; j++) { int max = 0; int index = 0; /** * 找出从前1位到前i-1位分成j-1段时的值与后面的值相乘得到的最大值 * 公式:m(i,j)=max{m(d,j-1)*w(d+1,i)} (1<d<i) */ for (int k = 0; k < i; k++) { if (maxValue[k][j - 1] * value[k + 1][i] > max) { max = maxValue[k][j - 1] * value[k + 1][i]; index = k + 1; } } //得到最大的乘积时,最后一个乘号的位置 bit[i][j] = index; maxValue[i][j] = max; } } }
全部的代码:
package 动态规划; import javax.swing.JOptionPane; /** * 求最大K乘积 * * @author ZDX * */ public class MaxK { int[] num; int[][] value; // 用来记录最大k乘积 int[][] maxValue; // 用来存储用户输入的分成的分数 int intDuan; // 用来记录乘号最后出现的位置 int[][] bit; int result; public MaxK() { // 得到要处理的字符串 String strNum = ""; while (strNum == null || strNum.equals("")) { strNum = JOptionPane.showInputDialog(null, "请输入要进行分解的整数"); } // 将字符串转化为字节数组 byte[] bt = strNum.getBytes(); // 初始化 num = new int[bt.length]; value = new int[bt.length][bt.length]; maxValue = new int[bt.length][bt.length]; bit = new int[bt.length][bt.length]; // 将得到的字节数组转化为整数数组 for (int i = 0; i < bt.length; i++) { num[i] = bt[i] - 48; } strNum = ""; while (strNum == null || strNum.equals("")) { strNum = JOptionPane.showInputDialog(null, "请输入要分成的段数:"); } intDuan = Integer.parseInt(strNum); maxValue(); } /** * 对得到的数组进行处理,得到最大K乘积 */ private void maxValue() { int size = num.length; /** * 先把value[i][j]初始化,其代表的是从i开始到j所代表的的整数i<j */ for (int i = 0; i < size; i++) { value[i][i] = num[i]; for (int j = i + 1; j < size; j++) { value[i][j] = value[i][j - 1] * 10 + num[j]; } } /** * 初始化maxValue第一列,即前i+1位,分成1段所得的最大乘积 * 初始化bit第一行和第一列,即当前i+1位分成1段时最后一个乘号的位置,和第一位分成i+1段时最后一个乘号出现的位置,都将他们的初始化为零 */ for (int i = 0; i < size; i++) { maxValue[i][0] = value[0][i]; bit[0][i] = 0; bit[i][0] = 0; } // 关键代码得maxValue[i][j]的值,即前i+1位分成j+1段时的最大乘积(因为下表从零开始) for (int i = 1; i < size; i++) { //分成二段到intDuan段 for (int j = 1; j < intDuan; j++) { int max = 0; int index = 0; /** * 找出从前1位到前i-1位分成j-1段时的值与后面的值相乘得到的最大值 * 公式:m(i,j)=max{m(d,j-1)*w(d+1,i)} (1<d<i) */ for (int k = 0; k < i; k++) { if (maxValue[k][j - 1] * value[k + 1][i] > max) { max = maxValue[k][j - 1] * value[k + 1][i]; index = k + 1; } } //得到最大的乘积时,最后一个乘号的位置 bit[i][j] = index; maxValue[i][j] = max; } } /** * 输出将前i位分成j段时所得到的最大值maxValue[i][j]一一输出 * result最终得到的是该数分成intDuan段相乘的最大值 */ for (int i = 0; i < size; i++) { for (int j = 0; j < intDuan; j++) { System.out.print(maxValue[i][j] + " "); result = maxValue[i][j]; } System.out.println(); } /** * 输出将前i位分成j段相乘的最大值时最后一个乘号的位置 */ for (int i = 0; i < size; i++) { for (int j = 0; j < intDuan; j++) { System.out.print(bit[i][j] + " "); } System.out.println(); } /** * 得到最终的相乘形式,例:23*41 */ String strOutput = ""; int i = size - 1; int j = intDuan - 1; while (j > 0) { System.out.println(bit[i][j]); strOutput = "*" + value[bit[i][j]][i] + strOutput; /** * value[bit[i][j]][i]表示的是从最后一个乘号到最后一位的值。这是一个迭代的过程, * 当下一次时原本的数据会将value[bit[i][j]][i]从启辰上去除,再进行处理 * 例:数据2341,分成三(j=2,j从0开始计数)段,则最大相乘形式为2*3*41,最后一位的下表(从零开始)i=3后一个乘号出现的位置是bit[i][j]=2,则value[bit[i][j]][i]=41, * 则下次对其进行处理的时候是23,剩下的是将其分成两段(j=1),则i=1,即i=bit[i][j]-1; */ i = bit[i][j] - 1; j--; } //将最前面的一个数字加到字符串上 strOutput = value[0][i] + strOutput; JOptionPane.showMessageDialog(null, "最大" + intDuan + "乘积为:" + result + "\n相乘格式为: " + strOutput, "结果", 1); } public static void main(String[] args) { new MaxK(); } }
测试如下:
相关推荐
最大K乘积问题: 设I是一个n位十进制整数。如果将I划分为k段,则可得到k个整数。这k个整数的乘积称为I的一个k乘积。试设计一个算法,对于给定的I和k,求出I的最大k乘积。 编程任务: 对于给定的I 和k,编程计算I ...
算法设计实验-最大k乘积问题 亲自用Dev-C++测试实验结果,没有任何问题!
"最大K乘积问题"是一个典型的算法问题,它涉及到从一组数值中找出前K个乘积最大的元素。这个问题在数据分析、机器学习以及优化问题中都有广泛应用。 首先,我们要理解问题的核心:给定一个整数数组nums和一个正整数...
C++实现从input.txt读取k值n值以及数据,计算最大k乘积,并将结果写入文件output.txt,压缩包包含文件readme.txt对代码做了简要介绍,将文件路径修改便可运行,如果想对算法深入了解可查看我的博客:...
实现3-13最大k乘积问题.cpp
最大K乘积问题 设I是一个n位十进制整数。如果将I划分为k段,则可得到k个整数。这k个整数的乘积称为I的一个k乘积。试设计一个算法,对于给定的I和k,求出I的最大k乘积。 编程任务: 对于给定的I 和k,编程计算I 的...
下面,我们将讨论动态规划经典问题算法,包括合唱队行、最大 k 乘积、0-1 背包问题、最长上升子序列、田忌赛马、花瓶插花等。 一、合唱队行 合唱队行是动态规划经典问题之一。该问题可以描述为:有 n 个人站在一排...
将一个整数字符串用*分隔成k段后,将每段数字相乘得到的最大乘机
输出结果则写入output.txt,只包含计算出的最大k乘积。 对于测试,我们可以设计不同规模的输入数据,例如一个5位数分成3段,以及一个6位数分成6段的情况,验证算法的正确性和效率。通过这样的实验,可以深入理解和...
文章也提到了一个关键的函数P(k),这个函数利用了h(k)和h(k+1)来界定n的范围,这个范围内的n分解后会得到一个最大的乘积。P(k)函数在不同条件下有不同的结果,这些结果都是通过对条件进行分析和计算得到的。 文章...
在本实验中,我们将深入探讨动态规划这一重要的算法思想,主要涵盖了五个具体的问题:最大k乘积问题、独立任务最优调度问题、最小m段和问题、字符串比较问题以及石子合并问题。动态规划是一种用于解决最优化问题的...
四川大学的这份算法设计报告详细诠释了这两种算法的应用,特别是在整数因子分解和最大k乘积问题中的运用。 在探讨整数因子分解问题时,报告指出了递归算法的核心思想:将一个大问题分解为若干个小问题,通过递归...
本篇将围绕武汉理工大学算法设计课程的两个实验进行深入探讨,分别是实验一中的分治法应用——中位数计算和Gray码生成,以及实验二中的动态规划策略——最大k乘积问题和游艇最少租金问题。这些实验旨在让学生理解和...
在这个主题下,我们可以看到几个典型的问题,包括最大子矩阵问题、整数划分问题和最大K乘积问题。下面我们将逐一深入探讨这些算法问题。 1. **最大子矩阵和问题**: 这个问题要求在给定的m行n列整数矩阵中找到一个...
引理2.1表明对于两个图G和H,其乘积图G×H的分数色数是G和H的分数色数的最大值。定理2.2进一步说明了如果G的分数色数等于其色数,且H的色数不超过G的分数色数,则乘积图G×H的分数色数与G的分数色数相等。 ### 知识...
另一个例子是最大k乘积问题,该问题要求将一个整数分成k段,并求出这k段组成的整数的最大乘积。通过回溯法,我们可以尝试不同的分割方式,每次分割后计算乘积,然后回溯以尝试其他可能的分割,最终找到最大乘积。 ...
接着,"最大k乘积"问题是一个寻找数组中k个元素乘积最大的情况。这里,我们需要考虑到如何有效地更新当前的最大乘积,同时保持k个元素的集合。动态规划可以通过维护两个有序集合(最大值和最小值),在每一步中找到...
根据给定文件的信息,我们可以深入探讨“最大m段乘积和最小m段和”的核心概念与算法实现。这个主题涉及到动态规划(Dynamic Programming)在数组处理中的应用,具体目标是找到一个数组中最大m段的乘积以及最小m段的...
通过遍历所有可能的插入位置和乘号数量,更新f[i][j]的值,并最终得到整个数字串插入K个乘号的最大乘积p(1, n, k)。 解题的关键在于,对于每个j(1≤j≤k),我们需要找到一个位置q,将数字串分为前后两部分,使得...