動態規劃-分蛋糕V2
阿新 • • 發佈:2020-06-27
分蛋糕:
有一塊矩形大蛋糕,長和寬分別是整數w?、h。現要將其切成m塊小蛋糕,
每個小蛋糕都必須是矩形、且長和寬均為整數。切蛋糕時,每次切一塊蛋糕,
將其分成兩個矩形蛋糕。請計算:最後得到的m塊小蛋糕中,最大的那塊蛋糕的面積下限。
假設w= 4,?h= 4,?m= 4,則下面的切法可使得其中最大蛋糕塊的面積最小。
假設w= 4,?h= 4,?m= 3,則下面的切法會使得其中最大蛋糕塊的面積最小:
Input
共有多行,每行表示一個測試案例。每行是三個用空格分開的整數w, h, m ,
其中1 ≤ w, h, m ≤ 20 , m ≤ wh. 當 w = h = m = 0 時不需要處理,
表示輸入結束。
Output
每個測試案例的結果佔一行,輸出一個整數,表示最大蛋糕塊的面積下限。
Sample Input
4 4 4
4 4 3
0 0 0
Sample Output
4
6
"""
# 4 4 3
"""
[
[[-1, -1, -1], [-1, -1, -1], [-1, -1, -1], [-1, -1, -1], [-1, -1, -1]],
[[-1, -1, -1], [1, inf, inf], [2, 1, inf], [3, 2, 1], [4, 2, 2]],
[[-1, -1, -1], [2, 1, inf], [4, 2, 2], [6, 3, 2], [8, 4, 3]],
[[-1, -1, -1], [3, 2, 1], [6, 3, 2], [9, 6, 3], [12, 6, 4]],
[[-1, -1, -1], [4, 2, 2], [8, 4, 3], [12, 6, 4], [16, 8, 【6】]]
]
【6】位置,表示w=4,h=4,d=2的值
思路:遞推就是就是後續的值是由前面計算過的值求出來的。
只要理解其中的一種情況,如:minBiggestArea[4][4][2]
求w=4,h=4,d=2的最大蛋糕的最小值
對蛋糕切1刀下去後,假設第1刀豎切,位置在w=3的位置,
那麼就分成了2塊蛋糕,那麼用剩下的刀數分別求這兩塊蛋糕的最大蛋糕的最小值
假設左邊最大蛋糕的最小值v1,右邊最大蛋糕的最小值v2,
max(v1,v2),兩者中的最大值,既是minBiggestArea[4][4][2]第一刀切在w=3位置
最大蛋糕的最小值。
總共可以切2刀,第1刀已經切了,那麼左右蛋糕最多隻能切1刀
其中一種情況:遍歷左邊切0刀,右邊只能切1刀
v1=minBiggestArea[3][4][0],v2=minBiggestArea[1][4][1]
其中一種情況:遍歷左邊切1刀,右邊只能切0刀
v1=minBiggestArea[3][4][1],v2=minBiggestArea[1][4][0]
minBiggestArea[4][4][2] = max(v1,v2)
因為不同的切法,max(v1,v2)能求出許多不同的值,題目要求最小的值,因此
需要從那麼多個值當中找出最小的值存到minBiggestArea[4][4][2]
python程式碼:
# minBigestArea三維列表,0:寬,1:高,2:共切幾刀,在w,h的長方形切m刀最大蛋糕的面積最小值 minBiggestArea = [] INF = float("inf") # w-寬度 h-高度 d-刀數 def BiggestCakeMinSize(w, h, d): global minBiggestArea # 寬度 for i in range(1, w+1): # 高度 for j in range(1, h+1): # 列舉共可以切的刀數 for k in range(1, d+1): if k+1 > i*j: minBiggestArea[i][j][k] = INF else: # 豎切 SV = INF sv, sh = 0, 0 # 列舉豎著切寬度的位置 for ii in range(1, i): for kk in range(0, k): sv = max(minBiggestArea[ii][j][kk], minBiggestArea[i-ii][j][k-1-kk]) SV = min(SV, sv) # 橫切 SH = INF # 列舉橫著切高度的位置 for jj in range(1, j): for kk in range(0, k): sh = max(minBiggestArea[i][jj][kk], minBiggestArea[i][j-jj][k-1-kk]) SH = min(SH, sh) minBiggestArea[i][j][k] = min(SV, SH) return minBiggestArea[w][h][d] def main(): global minBiggestArea while True: w, h, m = map(int, input().split()) if w == 0 and h == 0 and m == 0: break # 構建1個三維列表,因為列表的序號從0開始計算,為了計算方便w、h多增加1, # 列表中w、h位置0的值沒有意義,不儲存資料,僅為計算方便 # 三維列表從1開始儲存,初始化為-1,如果計算過,就儲存值下來,避免重複計算,提高效率 # m這個位置儲存的是刀數,要分成m塊,需要m-1刀,比如m=3,只需要2刀,所以只需要生成0、1、2 # 因此m的位置不需要增加1 minBiggestArea = [[[-1 for i in range(m)] for i in range(h+1)] for i in range(w+1)] # 先計算如果一刀都不切的情況下的值,最大蛋糕最小值即寬*高 for i in range(1, w+1): for j in range(1, h+1): minBiggestArea[i][j][0] = i*j """ [ [[-1, -1, -1], [-1, -1, -1], [-1, -1, -1], [-1, -1, -1], [-1, -1, -1]], [[-1, -1, -1], [1, -1, -1], [2, -1, -1], [3, -1, -1], [4, -1, -1]], [[-1, -1, -1], [2, -1, -1], [4, -1, -1], [6, -1, -1], [8, -1, -1]], [[-1, -1, -1], [3, -1, -1], [6, -1, -1], [9, -1, -1], [12, -1, -1]], [[-1, -1, -1], [4, -1, -1], [8, -1, -1], [12, -1, -1], [16, -1, -1]] ] """ # m塊蛋糕需要切m-1刀 optimalValue = BiggestCakeMinSize(w, h, m-1) print("最大蛋糕塊的面積下限為:%d" % optimalValue) return 0 if __name__ == '__main__': main()