DP36 如何切出最大长度乘积 Maximum Product Cutting @geeksforgeeks

Given a rope of length n meters, cut the rope in different parts of integer lengths in a way that maximizes product of lengths of all parts. You must make at least one cut. Assume that the length of rope is more than 2 meters.

Examples:

Input: n = 2
Output: 1 (Maximum obtainable product is 1*1)

Input: n = 3
Output: 2 (Maximum obtainable product is 1*2)

Input: n = 4
Output: 4 (Maximum obtainable product is 2*2)

Input: n = 5
Output: 6 (Maximum obtainable product is 2*3)

Input: n = 10
Output: 36 (Maximum obtainable product is 3*3*4)

1) Optimal Substructure: 
This problem is similar to Rod Cutting Problem. We can get the maximum product by making a cut at different positions and comparing the values obtained after a cut. We can recursively call the same function for a piece obtained after a cut.

Let maxProd(n) be the maximum product for a rope of length n. maxProd(n) can be written as following.

maxProd(n) = max(i*(n-i), maxProdRec(n-i)*i) for all i in {1, 2, 3 .. n}

2) Overlapping Subproblems
Following is simple recursive C++ implementation of the problem. The implementation simply follows the recursive structure mentioned above.


A Tricky Solution:
If we see some examples of this problems, we can easily observe following pattern.
The maximum product can be obtained be repeatedly cutting parts of size 3 while size is greater than 4, keeping the last part as size of 2 or 3 or 4. For example, n = 10, the maximum product is obtained by 3, 3, 4. For n = 11, the maximum product is obtained by 3, 3, 3, 2. Following is C++ implementation of this approach.


package DP;

public class MaxProductCutting {

	public static void main(String[] args) {
		System.out.println(maxProdRec(10));
		System.out.println(maxProdDP(10));
		System.out.println(maxProdTrick(10));
	}
	
	public static int maxProdRec(int n){
		if(n==0 || n==1){
			return 0;
		}
		int max = 0;
		for(int i=1; i<n; i++){
			// 1.只切一刀  2.切完一刀后,把余下的继续切
			int bigger = Math.max(i*(n-i), i*maxProdRec(n-i));
			max = Math.max(max, bigger);
		}
		
		return max;
	}
	
	// Time: O(n^2), space:O(n)
	public static int maxProdDP(int n){
		// maxProd[i]: 总长度为i的绳子能切出的最大乘积
		int[] maxProd = new int[n+1];
		maxProd[0] = maxProd[1] = 0;
		
		// Build the table maxProd[] in bottom up manner and return
		// the last entry from the table
		for(int i=1; i<=n; i++){		// 总长度为i
			int max = 0;
			for(int j=1; j<=i/2; j++){	// 切长度为j
				int bigger = Math.max(j*(i-j), j*maxProd[i-j]);
				max = Math.max(max, bigger);
			}
			maxProd[i] = max;
		}
		return maxProd[n];
	}
	
	// 规律:不断以3为单位长度切
	public static int maxProdTrick(int n){
		if(n==2 || n==3){		// n equals to 2 or 3 must be handled explicitly
			return n-1;
		}
		int res = 1;
		while(n > 4){		// Keep removing parts of size 3 while n is greater than 4
			n -= 3;
			res *= 3;		// Keep multiplying 3 to res
		}
		return n*res;		// The last part multiplied by previous parts
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值