前端學習(一)
阿新 • • 發佈:2022-04-28
title: 鋼條切割問題
date: 2022-05-10 20:42:52
tags: 動態規劃
鋼條切割問題
問題背景
現在有一個長度為10的鋼條,可以零成本將其切割成多段長度更小的鋼條,我們先要求出最大收益
鋼條長度 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
價格p | 0 | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 24 |
如果我們不切割的話可以獲得的最大收益為 24
如果我們按照 2 2 6 切割方法,收益為 27
所以不同的切割方法收益不同,我們尋求的就是收益最大的切割方法
問題定義
輸入:
- 鋼條的長度n
- 價格表pl(1≤ l ≤n):表示長度為l的鋼條價格
輸出:
- 求得一組切割方法,令收益最大化
問題觀察
-
假設鋼條能夠至多切割一次:有以下這幾種情況
我們就需要從這幾種切割情況中尋找出收益最大的,max{p[i] + p[10-i], p[10]}
-
如果鋼條能夠切割兩次:
我們可以現將鋼條切割出一段
然後再剩餘的鋼條中繼續切割
這時候 長度為8的就可以看做切割次數為一的那一種情況
這裡可能存在最優子結構和重疊子問題
問題結構分析
問題表示:
C[j]:切割長度為j的鋼條可得到的最大總收益
遞推關係的建立
C[j] = Max{p[i] + C[j-i], p[j]}
C[j] 表示從這j種情況中選出最大的哪一種
這裡面就存在最優子結構問題
自底向上的計算
我們通過 C[0] = 0
以後C[j] 的求導需要 依託於 C[1] ~ C[j - i] 這麼多種情況中的最優解來進行C[j]的求解
所以這是一種區間性動態規劃,每走一步都要依賴於一個區間的最優值
最優方案追蹤
遞迴出口:輸出的鋼條長度為n
演算法例項
鋼條長度 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
價格p | 0 | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 24 |
- 我們先初始化C[0] = 0
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
C[i] | 0 | ||||||||||
rec | 0 | ||||||||||
-
鋼條長度為1
這時候沒得選只能夠選擇1
i | 1 |
---|---|
1 |
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
C[i] | 0 | 1 | |||||||||
rec | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
1 |
- 鋼條長度為2:
有兩種情況
- 切割一刀:結果為p[1] + C[2-1] = 2
- 不切割:結果為p[2] = 5
從上面選擇情況最大的:不切割
i | 1 | 2 |
---|---|---|
2 | 5 |
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
C[i] | 0 | 1 | 5 | ||||||||
rec | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
1 | 2 |
- 鋼條長度為3:
有三種情況:
- 在1那切割一刀:C[3] = p[1] + C[3-1] = 1 + C[2] = 6
- 在2那切割一刀:C[3] = p[2] + C[3-2] = 5 + 1 = 6
- 不切割:C[3] = p[3] = 8
從上面選擇情況最大的:不切割
i | 1 | 2 | 3 |
---|---|---|---|
6 | 6 | 8 |
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
C[i] | 0 | 1 | 5 | 8 | |||||||
rec | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
1 | 2 | 3 |
- 鋼條長度為4:
有四種情況:
-
在一那切割一刀:C[4] = p[1] + C[3] = 1 + 8 = 9
-
在二那切割一刀:C[4] = p[2] + C[2] = 5 + 5 = 10
-
在三那切割一刀:C[4] = p[3] + C[1] = 8 + 1 = 9
-
不切割:C[4] = p[4] = 9
從上面選擇最大的哪一種情況:在二那切割一刀
i 1 2 3 4 9 10 9 9 i 0 1 2 3 4 5 6 7 8 9 10 C[i] 0 1 5 8 10 rec 0 1 2 3 4 5 6 7 8 9 10 1 2 3 2
- 剩下哪幾種情況不在一一列舉
演算法實現
'''
鋼條切割問題
這個演算法主要需要實現以下這幾種情況:
1.C陣列(記錄權值)
2.Rec陣列(追蹤效果)
3.i陣列(記錄C[i]的各種情況的權重)
'''
def steel_bar_cutting(price_list, C, Rec):
# 初始化i陣列
I = []
# 遍歷鋼條長度 從1-len(price_list)
for length in range(1, len(price_list)):
# 初始化最大值, 最大值下標
max_data = 0
max_index = 0
# 尋找切割鋼條的 幾種情況, 並尋找最大的值,和最大值的下標
for m in range(1, length+1):
m_data = price_list[m] + C[length-m]
I.append(m)
if m_data > max_data:
max_data = m_data
max_index = m
# 把上述幾種方案中最大值 賦值給C陣列對應的位置, 把切割位置賦值給對應的Rec位置
C[length] = max_data
Rec[length] = max_index
# 追蹤最優方案
def track(C, Rec):
length = len(C) - 1
i = length
print(f"最大獲利為:{C[i]}")
print("獲利方案為:")
while(length > 0):
print(f"在{Rec[i]}位置切一刀")
i = length - Rec[i]
length = i
# 初始化資料
price_list = [0,1,5,8,9,10,17,17,20,24,24]
C = [0 for i in range(len(price_list))]
Rec = [0 for i in range(len(price_list))]
steel_bar_cutting(price_list, C, Rec)
track(C, Rec)