剪绳子问题-动态规划

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Hanoch_wang/article/details/90647374

给你一根长度为n的绳子,请把绳子剪成m段(m,n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。请问k[m]可能的最大乘积是多少?例如,当绳子的长度为8时,我们把它剪成长度分别是2、3、3的三段,此时得到的最大的乘积是18.

可以把大问题分解成几个小问题,分解后每个小问题也存在最优解,如果把小问题的最优解组合起来能够得到整个问题的最优解,我们可以用动态规划解决这个问题。

动态规划解题的特点一:求一个问题的最优解。结合本题就是就割断绳子长度的乘积最大值。

动态规划解题的特点二:正整体最优解依赖于各个子问题的最优解。加入第一刀剪在i的位置,绳子变为i和n-i两段,同样用最优化的方法把这两段分别剪成若干段,使得各自剪出来的每段绳子的长度乘积最大。

动态规划解题的特点三:各个小问题之间还有重叠的部分。如长度为10,把10剪成4和6两段,f(2)又是f(4)和f(6)的公共的更小的子问题。

动态规划解题的特点四:由于子问题再分解大问题的过程中重复出现,为了避免重复求解子问题,我们可以用从下往上的顺序先计算小问题的最优解并存储下来,再以此为基础求取大问题的最优解。

对于此题在剪第一刀的时候,我们有n-1种选择,也就是一段绳子的可能长度分别是1,2,...,n-1,因此f(n)=max(f(i)*f(n-i))。这是一个从上至下的递归公式。由于递归会有很多重复的子问题,从而有大量不必要的重复计算。一个更好的办法就是按照从下往上的顺序计算,也就是说我们先得到f(2)、f(3),再得到f(4)、f(5),直到得到f(n).

代码:

public class CuttingRope01 {
	
	public static void main(String[] args) {
		CuttingRope01 rope = new CuttingRope01();
		Scanner sca = new Scanner(System.in);
		int length = sca.nextInt();
		System.out.println(rope.maxResult(length));
	}
	
	public int maxResult(int length) {
	    if(length < 0)  return -1;
	    int result[] = new int[length+1];
	    if(length < 2) return 0;
	    if(length == 2) return 1;
	    if(length == 3) return 2;
		result[0] = 0;
		result[1] = 1;
		result[2] = 2;
	    result[3] = 3;
	    for(int i = 4; i <= length; i++) {
	    	int  max = i;
	    	for(int j = 1; j <= i/2; j++) {
	    		int temp = result[j]*result[i-j];
	    		if(temp > max) {
	    			max = temp;
	    		}
	    	}
	    	result[i] = max;
	    }
		
		return result[length];
	} 
	
}

时间复杂度O(n^2),空间复杂度O(n)

猜你喜欢

转载自blog.csdn.net/Hanoch_wang/article/details/90647374