java,动态规划,算法导论之钢条切割(O(n)时间渐进性)

动态规划总结:

动态规划用于处理具有最优子结构,子问题重叠且互不相关的情况。由于子问题有所重叠,故此,为节省运行时间,每个子问题只求一次,通过“自顶向下带备忘录法”或“自底向上迭代法”来记录和应用已求得结果的子问题。能把递归结构次数从指数次降低到多项数次,使问题能快速求解。

动态规划和分治法把大问题化成小问题思想有点类似,却又有不同,分治法的子问题没有重叠。

思想步骤:1、分析最优子结构

2、递归定义最优解

3、求出最优解的值并记录信息

4、构造出最优解具体方案


钢条切割分析(渐进性可为O(n)):

以自底向上为例,算法导论上伪代码如下

BOTTOM-UP-CUT-ROD(p, n)

let r[0..n] be a new array

r[0] = 0

for j = 1 to n

    q = -∞

    for i = 1 to j

        q = max(q, p[i] + r[j - i])

    r[j] = q

return r[n]


其中,p是已知价格的钢条长度对应的价格,显然,p的长度是固定的了,为一个常数,而n可为任意大,则伪代码中第五和第六行(伪代码加粗部分)中,i迭代到j,而j可迭代到n,则当n大于p的长度时,第六行将发生数组溢出错误,实际上,第六行不应该迭代到j,而是迭代到

Math.min(j, p.length)即可。

则代码两层循环中,第一次O(n)次,第二次O(p.length)次即可。所以,总的迭代次数O(n)次,故时间渐进性为O(n)。


因为java面向对象的特性,故此,在代码中我增添了一点功能,可能会有点感觉污染了本文的标题,不过,以上分析只是我个人见解,不对之处还请指正微笑微笑


代码实现:

package dynamicProgramming;

import java.util.Arrays;

// r, s, p中的index对应相应的长度,size对应最大长度
public class BottomUpCutRod {
	private int size = 0; // 已计算最优解的最大长度
	private int capacity = 0; // r,s实际数组长度,初始化为最大长度的两倍
	private int[] r; // 存储最优解的价格
	private int[] s; // 存储最优解的切割方案
	private int[] p; // 价格表

	// 设置价格表,并进一步最优实现方案初始化
	public void setPrice(int[] p, int n) {
		if (p.equals(this.p)) // 价格表没有变化,直接返回
			return;
		this.p = Arrays.copyOfRange(p, 0, p.length);
		this.size = n;
		this.capacity = n * 2;
		r = new int[capacity];
		s = new int[capacity];
		r[0] = 0;
		initialProject(1, n);
	}

	// 返回长度为len时,可获得的最优总价格
	public int getBest(int len) {
		if (len > capacity - 1) {
			capacity = 2 * capacity; // 容量扩大两倍
			r = Arrays.copyOfRange(r, 0, capacity);
			s = Arrays.copyOfRange(s, 0, capacity);
		}
		if (len > size) {
			initialProject(size + 1, len);
			size = len;
		}
		return r[len];
	}

	// 返回长度为n时的最优切割方案
	public int[] getBestCut(int len) {
		getBest(len);
		StringBuilder sb = new StringBuilder();
		while(s[len] != len) {
			sb.append(s[len] + " ");
			len = len - s[len];
		}
		sb.append(len);
		String[] ss = sb.toString().split(" ");
		int[] result = new int[ss.length];
		for(int i = 0; i < ss.length; i++)
			result[i] = Integer.parseInt(ss[i]);
		return result;	
	}
	
	// 输出价格表及从1到size长度的对应最优价格和切割方案
	public void printResult() {
		System.out.print("        长度:");
		for(int i = 1; i <= size; i++)
			System.out.format("%-6d", i);
		System.out.println();
		System.out.print("        价格:");
		for(int i = 1; i < p.length; i++)
			System.out.format("%-6d", p[i]);
		System.out.println();
		System.out.print("最优价格:");
		for(int i = 1; i <= size; i++)
			System.out.format("%-6d", r[i]);
		System.out.println();
		System.out.print("最优切割:");
		for(int i = 1; i <= size; i++)
			System.out.format("%-6d", s[i]);
	}
	
	// 初始化从from到end长度的钢条最优解
	private void initialProject(int from, int end) {
		for (int j = from; j <= end; j++) {
			r[j] = -1;
			for (int i = 1; i <= Math.min(j, p.length - 1); i++) {
				int q = p[i] + r[j - i];
				if (q > r[j]) {
					r[j] = q;
					s[j] = i;
				}
			}
		}
	}

}


测试代码:

package dynamicProgramming;

import java.util.Arrays;

public class TestBottomUpCutRod {
	public static void main(String[] args) {
		int[] p = {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
		BottomUpCutRod b = new BottomUpCutRod();
		b.setPrice(p, 10);
		b.printResult();
		System.out.println();
		System.out.println("长度为18最优解: " + b.getBest(18) + "   切割方案: " + Arrays.toString(b.getBestCut(18)));
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值