[演算法學習筆記]動態規劃之鋼條切割問題
阿新 • • 發佈:2019-01-04
問題描述
有一個長度為n的鋼條需要切割成短鋼條出售,長度不同的鋼條售價也不同,如下:
長度i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
價格p[i] | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 30 |
那麼怎麼切割才能獲得最大利益呢
暴力解決思路
只要列出每種切割方案,然後比較一下哪種切割方案利潤最大不就可以了嗎(手動滑稽
假設有一個長度為4的鋼條,那麼有一下四中切割方案
編號 | 切割方案 | 利潤 |
---|---|---|
① | ■■■■ | 9 |
② | ■■■,■ | 9 |
③ | ■■,■■ | 10 |
④ | ■■,■,■ | 6 |
⑤ | ■,■,■,■ | 4 |
發現當鋼條長度為4時,切割成兩個長度為2的短鋼條利潤最大。而且當切割鋼條時,若切割完成後的鋼條長度小於等於1的話,則可以把這個鋼條看成規模更小的相同問題,用同樣的方法先求出這個短鋼條的最大利潤,然後比較所有組合的利潤,構成原問題的解。
鋼條切割問題滿足最優子結構的性質:問題的最優解由相關問題的最優解組合而成,而這些子問題可以獨立求解。
通過遞迴的求解方式可以寫出簡單的求解程式:從鋼條的左邊切割下一段長度為i的短鋼條,然後右邊為長度就為n-i的短鋼條,然後對右邊繼續遞迴求解,知道右邊的長度為0,則返回零。
#include <stdio.h>
#define max(a,b) (a>b?a:b)
#define INF 0x7fffff;
// 不同長度鋼條的價格
int p[11] = {
0,1,5,8,9,10,17,17,20,24,30
};
int cutROd(int p[], int n){
int i, q;
if(n == 0)
return 0;
q = -INF;
for(i = 1; i <= n; i++){
q = max(q, p[i] + cutROd(p, n - i));
}
return q;
}
int main(){
int n;
scanf("%d", &n);
printf("%d\n", cutROd(p, n));
return 0;
}
指數爆炸
圖樣圖森破啊,這個程式的複雜度是2^n,所以輸入大一點的數就會指數爆炸了,等半天結果才會出來,所以這樣寫太native了
更高效的方法
改進上面的程式
上面的程式之所以低效,因為有很多重複的計算啊,比如說計算長度為4的鋼條,便有多次計算了長度為2和3的最優解,更不要說在大一點的數要重複計算多少次了。但是,如果能避免這些重複計算的,演算法的效率就會非常高了,只要在第一次計算中吧結果記錄下來,下次需要用到的時候直接呼叫就可以了。
#include <stdio.h>
#define max(a,b) (a>b?a:b)
#define INF 0x7fffff;
int p[11] = {
0,1,5,8,9,10,17,17,20,24,30
};
int memoizedCutRodAux(int p[], int n, int r[]){
int q;
if(r[n] >= 0)
return r[n];
if(n == 0)
q = 0;
else{
q = -INF;
int i;
for(i = 1; i <= n; i++)
q = max(q, p[i] + memoizedCutRodAux(p, n-i, r)) ;
}
r[n] = q;
return q;
}
int memoizedCutRod(int p[], int n){
int r[11], i;
for(i = 0; i < 11; i++)
r[i] = -INF;
return memoizedCutRodAux(p, n, r);
}
int main(){
int n;
scanf("%d", &n);
printf("%d\n", memoizedCutRod(p, n));
return 0;
}
另一種解法
#include <stdio.h>
#define max(a,b) (a>b?a:b)
#define INF 0x7fffff;
int p[11] = {
0,1,5,8,9,10,17,17,20,24,30
};
int buttomUpCutRod(int p[], int n){
int r[n+1];
r[0] = 0;
int i, j;
for(i = 1; i <= n; i++){
int q = -INF;
for(j = 1; j <= i; j++)
q = max(q, p[j] + r[i - j]);
r[i] = q;
}
return r[n];
}
int main(){
int n;
scanf("%d", &n);
printf("%d\n", buttomUpCutRod(p, n));
return 0;
}