zoukankan      html  css  js  c++  java
  • 深度优先搜索-生日蛋糕

    生日蛋糕 (百练1190)
    要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
    设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时
    ,要求Ri > Ri+1且Hi > Hi+1。
    由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)
    的面积Q最小。令Q = Sπ
    请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
    (除Q外,以上所有数据皆为正整数)

    输入
    有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),
    表示蛋糕的层数为M。
    输出:仅一行,是一个正整数S(若无解则S = 0)。

    输入:
    100
    2
    输出:
    68

    思路:
    蛋糕的体积:V=Nπ=πR21H1+πR22H2+...+πR2nHn
    则:N=R21H1+R22H2+...+R2nHn
    其中(R1>R2>R3>...>Rn

    蛋糕的表面积:Q=Sπ=πR21+2πR1H1+2πR2H2+...+2πRnHn
    则:S=R21+2R1H1+2R2H2+...+2RnHn
    其中(R1>R2>R3>...>Rn且H1>H2>H3>...>Hn)

    当N取最大值10000时,最大半径是当h=1时,即r=100。同理,最大的h=10000

    深度优先搜索,枚举什么?
    枚举每一层可能的高度和半径。
    如何确定搜索范围?
    底层蛋糕的最大可能半径和最大可能高度
    搜索顺序,哪些地方体现搜索顺序?
    从底层往上搭蛋糕,而不是从顶层往下搭

    剪枝1:搭建过程中发现已建好的面积已经超过目前求得的最优表面
    积,或者预见到搭完后面积一定会超过目前最优表面积,则停止搭建(最优性剪枝)
    剪枝2:搭建过程中预见到再往上搭,高度已经无法安排,或者半径
    已经无法安排,则停止搭建(可行性剪枝)
    剪枝3:搭建过程中发现还没搭的那些层的体积,一定会超过还缺的
    体积,则停止搭建(可行性剪枝)
    剪枝4:搭建过程中发现还没搭的那些层的体积,最大也到不了还缺
    的体积,则停止搭建(可行性剪枝)

    假设构建2层蛋糕,最低层为r1,h1,第二层为r2,h2,公式如下:
    V=Nπ=πr1平方h1 + πr2平方h2,N=r1平方h1 + r2平方h2
    同理:蛋糕表面积=蛋糕最底层蛋糕的圆面积 + 每层蛋糕的侧面积
    因为每层蛋糕的顶面积刚好就是最底层蛋糕的圆面积
    Q=Sπ= πr1平方 + 2πr1h1 + 2πr2h2,提取π公因子
    S = r1平方 + 2r1h1 + 2r2h2

    python 代码实现:
     1 import math
     2 
     3 # N-蛋糕的总体积,M-层数
     4 N, M = 0, 0
     5 # 最优表面积,初值为无穷大
     6 minArea = float("inf")
     7 # 正在搭建中的蛋糕的表面积
     8 area = 0
     9 # 统计循环的次数
    10 num = 0
    11 # 当前体积
    12 currentVolume = 0
    13 
    14 # 要用m层去凑体积v,最底层半径不能超过r,高度不能超过h
    15 # 求出最小表面积放入minArea
    16 def Dfs(v, m, r, h):
    17     global N, M, minArea, area, num, currentVolume
    18     # m=0,v=0时,说明蛋糕搭建成功,因为的递减,m=0说明不需要搭层数了
    19     # 而且v=0,说明体积大小也搭建符合题目的要求了,v!=0,说明已经搭到
    20     # 顶层蛋糕了,但是体积没有搭到输入N的要求,所以失败了
    21     if m == 0:
    22         if v == 0:
    23             # 找到一个最优值与之前的最优值进行比较,如果更小则替换
    24             minArea = min(minArea, area)
    25             return
    26         else:
    27             return
    28     # 做m层蛋糕,但是体积v是0或者小于0是做不到的
    29     if v <= 0:
    30         return
    31     # 半径i从最大半径r开始依次递减1,直到m,因为如果要做m层蛋糕,
    32     # 最底层的蛋糕的半径最小值为m,同理最底层蛋糕的高度最小值也为m
    33     # 因为题目要求是整数,而且逐层半径、高度最小相差1
    34     for i in range(r, m-1, -1):
    35         # S = r1平方+各层蛋糕的侧面积
    36         # 蛋糕的底面积
    37         if m == M:
    38             area = i * i
    39         for j in range(h, m-1, -1):
    40             # currentVolume表示搭好的当前蛋糕的体积
    41             currentVolume = currentVolume + (i*i*j)
    42             # 剪枝:如果按此半径和高度,搭好的蛋糕的体积超过输入的N,则该方案不可行
    43             if currentVolume > N:
    44                 # 深度遍历需要回溯,之前加过这个值了,但是该条路径走不通,因此要把之前加的值减回去
    45                 currentVolume -= (i * i * j)
    46                 continue
    47             area += 2 * i * j
    48             # 剪枝:如果计算出正在搭建的表面积已经大于曾经计算出的最优表面积
    49             # 则不需要再往下搭建了,即使能搭建出来也不是最优的表面积
    50             if area > minArea:
    51                 # 该条路径走不通,因此要把之前加的值减回去
    52                 area -= 2 * i * j
    53                 continue
    54             num += 1
    55             Dfs(v-i*i*j, m-1, i-1, j-1)
    56             # 走过的路重新往回走,需要把原来增加的值减回去,以保证下次新的走法走到该点时,
    57             # area、currentVolume的值是与原初始化的值
    58             area -= 2 * i * j
    59             currentVolume -= (i * i * j)
    60 
    61 
    62 def main():
    63     global N, M, minArea, num
    64     N, M = map(int, input().split())
    65     # 这里对半径和高度都是做个初略的假设
    66     # 最大半径是假设蛋糕就1层,高度是1的情况,根据公式,可以对N开根号即可得最大值
    67     # 最大高度是假设蛋糕的半径是1的情况,N就是高度的最大值
    68     Dfs(N, M, int(math.sqrt(N)), N)
    69     if minArea == float("inf"):
    70         print("%d" % 0)
    71     else:
    72         print("S = %d,循环次数:%d" % (minArea, num))
    73 
    74 
    75 if __name__ == '__main__':
    76     main()


  • 相关阅读:
    自食其力!ASP.NET 4打造HTML5视频控件
    delphi 拖放操作http://topic.csdn.net/t/20030306/10/1497344.html?1026446129
    delphi开发的小技巧http://www.cto360.com/a/5000086716.shtml
    TThread 类 详细解析 (原帖 华夏黑客同盟)http://www.cppblog.com/Khan/archive/2006/11/21/15503.html
    delphi 多线程同步 互斥变量,信号量,事件对象。http://www.bianceng.cn/Programming/Delphi/200912/12689.htm
    如何利用socket进行HTTP访问http://blog.csdn.net/sanfengshou/archive/2011/03/07/6228250.aspx
    TCP, Scoket, HTTP
    Delphi开发嵌入式IE浏览器监控程序http://www.pasou.cn/edu/html/List3899_3.html
    Delphi实现网络蚂蚁和FlashGet的悬浮窗口,拖动
    delphi调用C#写的web服务例子(重点 InvRegistry.RegisterInvokeOptions(TypeInfo(ServiceSoap), ioDocument);)
  • 原文地址:https://www.cnblogs.com/an-wl/p/13282675.html
Copyright © 2011-2022 走看看