动态规划-隔钢条-算法导论-2021/1/1

动态规划-割钢条

下面给出一个简单的题目,分析过程我借鉴的是算法导论那本书的例子。顺便给自己做一个笔记。
然后体验一下人家的分析过程,并且把过程抽象化,对算法的设计有多大作用。

在这里插入图片描述

第一:看了题目之后,我们首先想到的是先切割,然后再对应表格计算价钱。
比如长度L=4时,如上图对应的有八种切割方式。当切割为两段时,出售的价钱是最高 = 10。当L=1时,是不切,价钱为1。L=2时也是不切,价钱为5。当L = 3时有四种切割方案不切的时候价钱才是最高的。


总结上面的,我可以得出,每一段钢条都有其对应的最优解。所以我们设,L = n时,切成k段时有最优解
最优切段:L{n} = i1 + i2 + … + ik(1 <= k <= n) —> i1…代表切断的长度
最优价格:R{n} = P{i1} + P{i2} + … + P{ik}(1 <= k <= n)
上面两个公式时对每一段钢条的最优切割进行抽象,对应的就是最优价钱。我们知道,每一段钢条切割之后,会变成两段,然后再求两个段的最优解。就比如L = 4,分为两段的时候是L = 2 + 2,2本身就是最优解,所以L = 4时,P = 10。
所以当我们求n段的最优解时,有P{n} = max(R{n},R{i1}+R{n-i1},…,R{n-i1}+R{i1}),这公式的意思是,从所有的切断中求最优解。


自顶向下的概念,这个的意思是,要求子问题x的时候、得调用自身(递归)把x里面的子问题再进行求
解,把x所有的子问题求解完毕,才得到x本身。比如:再上面的图中,要对L = 4进行求解的时候,切
为两段时有1,3两中长度,这个时候得对3求最优解才能得到从第一个位置切i=1时的最优解。

自顶向下的递归—伪代码
CUT-ROD(p,n)
if(n == 0) return 0
q = Integer.MIN_VALUE
------- for i = 1 to n
----------- //这个动态转移方程就是上面公式P{n},可以好好体会一下
----------- q = max(p[i]+CUT-ROD(p,n-i),p)
return q


上面伪代码的p代表的是价格表,n代表的是钢条一共多长


自顶向下带备忘录的递归—伪代码
CUT-ROD(p,r,n)
if(r[n]>0) return r[n]
if(n==0) return 0
for i = 0 to p.length
------ r[i] = p[i]//初始化
q = Integer.MIN_VALUE
------ for i = 1 to n
--------- q = max(r[i] + CUT-ROD(p,r,n-i),q)
------ r[i] = q//记录最优解
return r[n]


上面是带备忘录的自顶向下的动态规划


自底向上:再对x子问题进行求解的时候,先把它用到的子问题进行求解。这个跟自顶向上没有本质的
区别,主要的区别在于求解问题规模的顺序。

伪代码:
CUT-ROD(p,n)
if(r[n]>0) return r[n]
if(n==0) return 0
for i = 0 to p.length
------ r[i] = p[i]//初始化
q = Integer.MIN_VALUE
------ for i = 1 to n
--------- for j = 1 to i
------------ q = max(r[i]+r[i-j],q)
------ r[i] = q//记录最优解
return r[n]

在这里插入代码片
//至顶向下--递归
	public int cutrod(int[] priceTbale,int n) {
		if (n == 0) return 0;
		int price = Integer.MIN_VALUE;
		for (int i = 1; i <= n; i++) {
			price = Math.max(priceTbale[i]+cutrod(priceTbale, n-i), price);
		}
		return price;
	}
//自顶向下--备忘递归
public int memoizedCutRodAux(int dp[],int n) {
		if (n == 0) return 0;
		if (n > 10 && dp[11] > 10) {
			return dp[n];
		}
		int value = Integer.MIN_VALUE;
		for (int i =1; i <= n; i++) {
			value = Math.max(dp[i]+memoizedCutRodAux(dp,n-i),value);
		}
		dp[n] = value;
		return value;
	}
	public int memoizedCutRod(int price[],int n) {
		int dp[] = new int[n+1];
		for (int i = 1; i < price.length; i++) {
			dp[i] = price[i];
		}
		return memoizedCutRodAux(dp,n);
	}
//自底向上
public int bottomUpCutRod(int price[],int n) {
		int r[] = new int[n+1];
		r[0] = 0;
		for (int i = 1; i < price.length; i++) {
			r[i] = price[i];
		}
		for (int i = 1; i <= n; i++) {
			int q = Integer.MIN_VALUE;
			for (int j = 1; j <= i; j++) {
				q = Math.max(q, r[j]+r[i-j]);
			}
			r[i] = q;
		}
		return r[n];
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值