zoukankan      html  css  js  c++  java
  • 题解 P1731 【[NOI1999]生日蛋糕】

    解题思路

    - 深度优先搜索,枚举什么?

    枚举每一层可能的高度和半径。       

    - 如何确定搜索范围?

    底层蛋糕的最大可能半径和最大可能高度

    - 搜索顺序,哪些地方体现搜索顺序?

    从底层往上搭蛋糕,而不是从顶层往下搭
    在同一层进行尝试的时候,半径和高度都是从大到小试

    那么如何剪枝呢?

    剪枝

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

      代码

      #include <iostream>
      #include <vector>
      #include <cstring>
      #include <cmath>
      using namespace std;
      int N,M;
      int minArea = 1 << 30; //最优表面积
      int area = 0; //正在搭建中的蛋糕的表面积
      int minV[30]; // minV[n]表示n层蛋糕最少的体积
      int minA[30]; // minA[n]表示n层蛋糕的最少侧表面积
      int main()
      {
      cin >> N >> M ;//M层蛋糕,体积N
      minV[0] = 0;
      minA[0] = 0;
      for( int i = 1; i<= M; ++ i) {
      minV[i] = minV[i-1] + i * i * i; //第i层半径至少i,高度至少i
      minA[i] = minA[i-1] + 2 * i * i;
      }
      if( minV[M] > N )
          cout << 0 << endl;
      else {
      int maxH = (N - minV[M-1])/(M*M) + 1;//底层最大高度
      //最底层体积不超过 (N-minV[M-1]),且半径至少M
      int maxR = sqrt(double(N-minV[M-1])/M) + 1;//底层高度至少M
      area = 0;
      minArea = 1 << 30;
      Dfs( N,M,maxR,maxH);
      if( minArea == 1 << 30)
          cout << 0 << endl;
      else
          cout << minArea << endl;
      }
      }
      void Dfs(int v, int n,int r,int h)
      //要用n层去凑体积v,最底层半径不能超过r,高度不能超过h
      //求出最小表面积放入 minArea
      {
      if( n == 0 ) {
          if( v )
          return;
          else {
          minArea = min(minArea,area);
          return;
        }
      }
      if( v <= 0)
          return ;
      if( minV[n] > v ) //剪枝3
          return ;
      if( area + minA[n] >= minArea) //剪枝1
          return ;
      if( h < n || r < n ) //剪枝2
          return ;
      if( MaxVforNRH(n,r,h) < v ) //剪枝4
      //这个剪枝最强!没有的话, 5秒都超时,有的话, 10ms过!
          return;
      //for( int rr = n; rr <= r; ++ rr ) { 这种写法比从大到小慢5倍
      for( int rr = r; rr >=n; -- rr ) {
      if( n == M ) //底面积
          area = rr * rr;
      for( int hh = h; hh >= n ; --hh ) {
        area += 2 * rr * hh;
        Dfs(v-rr*rr*hh,n-1,rr-1,hh-1);
        area -= 2 * rr * hh;
      }
      }
      }
      int MaxVforNRH(int n,int r,int h)
      { //求在n层蛋糕,底层最大半径r,最高高度h的情况下,能凑出来的最大体积
      int v = 0;
      for(int i=0;i<n ;++i )
          v+=(r - i ) *(r-i) * (h-i);
      return v;
      }
       

      还有什么可以改进

      1) 用数组存放 MaxVforNRH(n,r,h)MaxVforNRH(n,r,h)MaxVforNRH(n,r,h) 的计算结果,避免重复计算

  • 相关阅读:
    精益产品探索
    vue 之 pdf预览
    arcgis js 之 渔网工具(调用地图服务)
    arcgis js之卷帘工具
    arcgis js之调用wms服务
    vue-cli3 本地数据模拟后台接口
    cmd设置电脑自动关机
    Arcgis js之web墨卡托(3857)转经纬度坐标(4326)
    arcgis js之地图分屏同步
    arcgis之gp服务发布
  • 原文地址:https://www.cnblogs.com/Sworddust/p/11427861.html
Copyright © 2011-2022 走看看