动态规划-分蛋糕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()

 

posted @ 2020-06-27 13:06  StudyNLP  阅读(518)  评论(0编辑  收藏  举报