动态规划-分蛋糕V2
分蛋糕:
有一块矩形大蛋糕,长和宽分别是整数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()