动态规划-分蛋糕V1

分蛋糕:
有一块矩形大蛋糕,长和宽分别是整数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

实现:递归原理实现:设 DFS(w,h,m)表示宽为w,高为h的蛋糕,被切m刀后,
最大的那块蛋糕的面积最小值,要M块蛋糕,只需要切M-1刀
题目就是要求 DFS(W,H,M-1)
边界条件:1.w * h < m + 1 INF 2.m == 0 w*h
SV为第一刀竖着切时能得到的最好结果,SH为第一刀横着切时能得到的最好结果,
DFS(w,h,m) = min(SV,SH)
SV=min{ Si,i=1...w-1},其中:Si=为第一刀左边宽为i的情况下的最好结果
Si = min{max(ways(i,h,k),ways(w-i,h,m-1-k)),k=0... m-1}

python算法实现:
 1 # 4 4 3
 2 # [
 3 # [[-1, -1, -1], [-1, -1, -1], [-1, -1, -1], [-1, -1, -1], [-1, -1, -1]],
 4 # [[-1, -1, -1], [1, -1, -1], [2, -1, -1], [3, -1, -1], [4, 2, -1]],
 5 # [[-1, -1, -1], [2, -1, -1], [4, -1, -1], [6, -1, -1], [8, 4, -1]],
 6 # [[-1, -1, -1], [3, -1, -1], [6, -1, -1], [9, -1, -1], [12, 6, -1]],
 7 # [[-1, -1, -1], [4, 2, -1], [8, 4, -1], [12, 6, -1], [-1, -1, 6]]
 8 # ]
 9 # DFS(4,4,2) = max(DFS(3,4,1),DFS(1,4,0))
10 # 6 =  max(6,4)
11 
12 # minBigestArea三维列表,0:宽,1:高,2:共切几刀,在w,h的长方形切m刀最大蛋糕的面积最小值
13 minBiggestArea = []
14 INF = float("inf")
15 
16 
17 # 竖着切
18 def SV(w, h, k):
19     sv = INF
20     # 第一刀竖着切,因为是整数,刀的位置在1——w之间,遍历第一刀切的位置
21     for i in range(1, w):
22         # 第一刀切下去了,那么就会产生左右两块蛋糕,剩下切的刀数就是0——k-1,所以遍历循环的范围是k
23         # 第一刀切下去后,产生2块蛋糕,那么对左边的蛋糕可能切几刀,取值从0——k-1
24         # 知道左边切下去的刀数了,那么就可以计算出还剩余的刀数就给右边来切
25         # 以4 4 3为例,如果第一刀切的位置为3,那么就会产生2块蛋糕,左边w=3,h=4 ,右边w=1,h=4
26         # 竖切的情况:
27         # DFS(4,4,2) = max(DFS(3,4,0),DFS(1,4,1))或者max(DFS(3,4,1),DFS(1,4,0))
28         # 因为我们需要找最大那块蛋糕的值,因此要取左右2块蛋糕的max值
29         # 那么不同的切法,最大那块蛋糕的值有许多种,题目要求最小的,所以最后就有个min
30         for kk in range(0, k):
31             # 求1切下去后左边蛋糕在i,h,kk的情况下最大蛋糕的最小值
32             leftValue = DFS(i, h, kk)
33             # 求1切下去后右边边蛋糕在w-i,h,k-1-kk的情况下最大蛋糕的最小值
34             rightValue = DFS(w-i, h, k-1-kk)
35             # 左右蛋糕最大蛋糕的最小值求出了,合起来比较,那么sv在w、h、k下最大蛋糕的最小值即可算出
36             sv = min(sv, max(leftValue, rightValue))
37     return sv
38 
39 
40 # 横着切与竖的原理是一样的,唯一区别这里是w不变,h变了
41 def SH(w, h, k):
42     sh = INF
43     for i in range(1, h):
44         for kk in range(0, k):
45             leftValue = DFS(w, i, kk)
46             rightValue = DFS(w, h-i, k-1-kk)
47             sh = min(sh, max(leftValue, rightValue))
48     return sh
49 
50 
51 # w-宽度 h-高度 k-共切几刀
52 def DFS(w, h, k):
53     global minBiggestArea
54     # 如果该位置的最大蛋糕最小值已经计算好了,不需要重复计算,直接读出
55     if minBiggestArea[w][h][k] != -1:
56         return minBiggestArea[w][h][k]
57     # w=4,h=4,因为要求蛋糕的边是整数,因此最多可以产生16块小蛋糕,也就是最多可以切15刀
58     # 如果切16刀,蛋糕分不出17块,完成不了,因此返回无穷大
59     if w * h < k + 1:
60         minBiggestArea[w][h][k] = INF
61         return minBiggestArea[w][h][k]
62     # 如果一刀都不切,那么w*h就是最大蛋糕的最小值
63     if k == 0:
64         minBiggestArea[w][h][k] = w * h
65         return minBiggestArea[w][h][k]
66     # 因为蛋糕第一刀切下去,有竖、横两个方向,所以要分别求
67     # 第一刀竖着切最大蛋糕的最小值,横着切所得最大蛋糕的最小值
68     # 然后再对这2个取最小值,即得该大小蛋糕,共切几刀的最大蛋糕最小值
69     minBiggestArea[w][h][k] = min(SV(w, h, k), SH(w, h, k))
70     return minBiggestArea[w][h][k]
71 
72 
73 def main():
74     global minBiggestArea
75     while True:
76         w, h, m = map(int, input().split())
77         if w == 0 and h == 0 and m == 0:
78             break
79         # 构建1个三维列表,因为列表的序号从0开始计算,为了计算方便w、h多增加1,
80         # 列表中w、h位置0的值没有意义,不存储数据,仅为计算方便
81         # 三维列表从1开始存储,初始化为-1,如果计算过,就存储值下来,避免重复计算,提高效率
82         # m这个位置存储的是刀数,要分成m块,需要m-1刀,比如m=3,只需要2刀,所以只需要生成0、1、2
83         # 因此m的位置不需要增加1
84         minBiggestArea = [[[-1 for i in range(m)] for i in range(h+1)] for i in range(w+1)]
85         # print(minBigestArea)
86         # w-宽度、h-高度,函数的第3个参数表示总共刀数,切m-1刀,即可得到m块蛋糕
87         optimalValue = DFS(w, h, m-1)
88         print("最大蛋糕块的面积下限为:%d" % optimalValue)
89 
90     return 0
91 
92 
93 if __name__ == '__main__':
94     main()

 



posted @ 2020-06-24 19:46  StudyNLP  阅读(632)  评论(0编辑  收藏  举报