zoukankan      html  css  js  c++  java
  • 深搜的剪枝技巧(二)——生日蛋糕(优化搜索顺序、可行性剪枝,最优性剪枝)

    生日蛋糕(优化搜索顺序、可行性剪枝,最优性剪枝)

    • 问题描述

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

      • 第一行为 N ((N leq 10000))。表示待制作的蛋糕体积为 (Npi)
      • 第二行为 M ((Mleq 20)),表示蛋糕的层数为 M
    • 输出格式

      • 输出仅一行,是一个整数 S (若无解则 S = 0)
    • 样例输入

      100
      2
      
    • 样例输出

      68
      

      附:圆柱公式:体积 (V = pi R^2H);侧面积:(A^{'} = 2pi RH);底面积:(A = pi R^2)

    • 思路分析——枚举每一层可能的高度和半径。确定搜索范围,即底层蛋糕的最大可能半径和最大可能高度。确定搜索顺序,从底层往上搭蛋糕。

    • 剪枝思路

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

      #include <iostream>
      #include <cmath>
      using namespace std;
      
      int N,M;
      int minArea = 1 << 30;
      int area = 0;
      
      void Dfs(int v,int n,int r,int h);
      
      int main()
      {
          cin>>N>>M;
          int MaxR = sqrt(N);   //粗略估计,忽略 π
          int MaxH = N;
          Dfs(N,M,MaxR,MaxH);
          if(minArea == 1 << 30)
              cout<< 0 <<endl;
          else
              cout<< minArea <<endl;
          return 0;
      }
      
      void Dfs(int v,int n,int r,int h)
      {
          if(n == 0)
          {
              if(v)
                  return;
              else
              {
                  minArea = min(minArea,area);
                  return;
              }
          }
          if(v <= 0)
              return;
          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;
              }
          }
      }
      
    • 代码(剪枝修改过的)

      #include <iostream>
      #include <cmath>
      using namespace std;
      
      int N,M;
      int minArea = 1 << 30;
      int minA[22] = {0},minV[22] = {0};
      int area = 0;
      
      int maxVJudge(int m, int r, int h);
      void Dfs(int v,int n,int r,int h);
      
      int main()
      {
          cin>>N>>M;
          for(int i = 1; i <= M; i++)
          {
              minA[i] = minA[i-1] + 2 * i * i;
              minV[i] = minV[i-1] + i * i * i;
          }
          int MaxH = (N - minV[M-1]) / (M * M) + 1;//最大的高度
          int MaxR = sqrt((N - minV[M-1]) / M) + 1;//最大的体积
          Dfs(N,M,MaxR,MaxH);
          if(minArea == 1 << 30)
              cout<< 0 <<endl;
          else
              cout<< minArea <<endl;
          return 0;
      }
      
      int maxVJudge(int m, int r, int h)
      {
          int maxV = 0;
          for(int i = 0; i < m; i++)
              maxV += (r-i) * (r-i) *(h-i);
          return maxV;
      }
      
      void Dfs(int v,int n,int r,int h)
      {
          if(n == 0)
          {
              if(v)
                  return;
              else
              {
                  minArea = min(minArea,area);
                  return;
              }
          }
          if(v<= 0) // 可行性剪枝1
              return ;
          if(minV[n] > v)//可行性剪枝2
              return ;
          if(maxVJudge(n,r,h) < v)//可行性剪枝3
              return ;
          if(minA[n]+area >= minArea) // 最优性剪枝
              return;
          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;
              }
          }
      }
      
      
  • 相关阅读:
    android animation
    android手机屏幕分辨率 及 sp dip(dp) px 区别 及高中低分辨率时处理
    android ExpandableListView
    android ImageView 之 android:scaleTye=" "
    android popupwindow
    如何使用 TransactSQL 编写作业脚本(企业管理器)
    线程访问临界区的问题 实例,需解决
    企业信息化
    使用Installshield制作asp,asp.net应用的安装程序
    Linux 系统目录结构
  • 原文地址:https://www.cnblogs.com/NikkiNikita/p/9474502.html
Copyright © 2011-2022 走看看