zoukankan      html  css  js  c++  java
  • 动态规划-分蛋糕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()


  • 相关阅读:
    树上路径
    [HNOI2017]礼物
    Spoj 8372 Triple Sums
    [Swerc2014 C]Golf Bot
    【bzoj2194】快速傅立叶之二 FFT
    Linux下perl模块安装
    angularjs form表单验证
    Angularjs兼容IE
    input file限制上传文件类型
    angularjs判断页面数据是否渲染完成
  • 原文地址:https://www.cnblogs.com/an-wl/p/13189461.html
Copyright © 2011-2022 走看看