动态规划表格法和备忘录法解决切木材问题

3.4 切木材问题(Rod-cutting problem)

3.4.1 问题描述

给一个长度为17的木材,可以切成小段卖出,价格根据小段的长度不同而不同。如何通过切成小段卖出尽可能高的总价钱?

3.4.2 算法思路

总体思路:
① 假如我们只有1米长的木材,那么就直接按1米的价格卖;
② 假如我们有2米长木材,那么可以切成两段卖(1+1=2元)或者直接按2米卖(4元),所以两米时我们不切直接卖;
③ 假如我们有3米,那么我们可以直接按3米卖(5元),或者切成一段1米和一段2米(1+4=5元),此时,两种方案都行,都能取到最大收益5元。*注意:这里不能够切成三段1米卖,因为一旦有2米,我们就直接按2米卖获得的收益最高,所以不能把2米再切成两段1米。*这就是我们解法的关键点,我们后面一旦遇到2米,就直接看Length=2时的value,它代表着2米的最高利益。
依此类推…
④ 假如我们有10米,那么可以直接10米卖(30元)或者切成1米和9米(1+24=25元),或者切成2米和8米(4+20=24元),…,或者5米和5米(10+10=20元),把所有可能进行比较,最终选择其中价值最高的直接10米卖也就是,30元。
一旦超过10米之后,就没有直接卖的价格了,此时就只需要比较切开卖法的价格。

动态规划表格法和备忘录法解决切木材问题_第1张图片

动态规划思想:

  • 问题分阶段:把length=n的大问题,分为了一个个小问题
  • 阶段有依赖:当我们算到后面大长度的时候,一旦出现某个小长度,我们就可以直接去看对应长度的value值,它代表着这个长度的最大收益,当我们在处理大问题时,都依赖于之前小问题的解。
  • 依赖有重合:当我们在处理大长度的时候,就不用重复计算小长度的买法,避免了重复计算。

3.4.3 表格法代码实现

//表格法
public static int getValue(int[] cut_value,int rod_length){
	int[] rod_value=new int[rod_length];
	rod_value[0]=cut_value[0];//长度为1时,木材价值直接等于对应价格
	for(int i=1;i<rod_length;i++){
		/*核心代码*/
		rod_value[i]=cut_value[Math.min(i,cut_value.length-1)];//木材价值value先初始化为对应长度的价格price,如果木材长度超过提供价格的木材长度,就直接使用最长长度的价格。
		for(int j=0;j<=i/2;j++){
			rod_value[i]=Math.max(rod_value[i],rod_value[j]+rod_value[i-j-1]);//对应长度木材的价格,依次首尾相加的价格里面取其大者
		}
	}
	return rod_value[rod_length-1];
}

3.4.4 备忘录法代码实现

//备忘录法
public static int getValueByMemoization(int[] cut_values, int rod_length) {
	int[] rod_values = new int[rod_length];
	rod_values[0] = cut_values[0];
	return getValueByMemoization(cut_values, rod_length, rod_values);
}

private static int getValueByMemoization(int[] cut_values, int rod_length, int[] rod_values) {
	if( rod_values[rod_length-1]>0)//数值已经存在则无需求解
		return rod_values[rod_length-1];
	rod_values[rod_length-1] = cut_values [Math.min(rod_length-1,cut_values.length-1)];//木材价值value先初始化为对应长度的价格price,如果木材长度超过提供价格的木材长度,就直接使用最长长度的价格。
	for(int j=0;j<=(rod_length-1)/2;j++) {
		rod_values[rod_length-1] = Math. max( rod_values[rod_length-1],
		getValueByMemoization(cut_values, j+1, rod_values) +getValueByMemoization(cut_values, rod_length-j-1,  rod_values));
	}
	return  rod_values[rod_length-1];
}

3.4.5 算法复杂度

算法复杂度:Θ(n2)
分析:每算出一个子长度i对应的值,都要经过i/2次比较,若木材总长度为n,则需要求出n个子长度,所以Θ(n2)

你可能感兴趣的:(算法设计与分析,动态规划,算法,表格法,备忘录法,切木头问题)