最大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段和问题、字符串比较问题以及石子合并问题。动态规划是一种用于解决最优化问题的...
本篇将围绕武汉理工大学算法设计课程的两个实验进行深入探讨,分别是实验一中的分治法应用——中位数计算和Gray码生成,以及实验二中的动态规划策略——最大k乘积问题和游艇最少租金问题。这些实验旨在让学生理解和...
在这个主题下,我们可以看到几个典型的问题,包括最大子矩阵问题、整数划分问题和最大K乘积问题。下面我们将逐一深入探讨这些算法问题。 1. **最大子矩阵和问题**: 这个问题要求在给定的m行n列整数矩阵中找到一个...
递归用于因子分解,强调了问题的分治策略,而动态规划则在最大k乘积问题中展示了如何通过存储和利用子问题的解来达到优化计算效率的目的。这两种算法都是算法设计和分析的重要工具,广泛应用于各种软件开发和数据...
引理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,将数字串分为前后两部分,使得...