動態規劃-隔鋼條-演算法導論-2021/1/1

月小貓發表於2021-01-01

動態規劃-割鋼條

下面給出一個簡單的題目,分析過程我借鑑的是演算法導論那本書的例子。順便給自己做一個筆記。
然後體驗一下人家的分析過程,並且把過程抽象化,對演算法的設計有多大作用。

在這裡插入圖片描述

第一:看了題目之後,我們首先想到的是先切割,然後再對應表格計算價錢。
比如長度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];
	}

相關文章