• 【POJ No. 1190】 生日蛋糕


    POJ No. 1190】 生日蛋糕

    POJ 题目地址

    在这里插入图片描述

    【题意】

    制作一个体积为N π的M 层生日蛋糕,每层都是一个圆柱体。设从下往上数第i (1≤i ≤M )层蛋糕是半径为Ri 、高度为Hi 的圆柱。当i Ri +1 且Hi >Hi +1 。由于要在蛋糕上抹奶油,所以为了尽可能节约经费,希望蛋糕外表面(底层的下底面除外)的面积Q 最小。

    令Q =S π,对给出的N 和M ,找出蛋糕的制作方案(适当的Ri 和Hi 的值),使S 最小。除Q 外,以上所有数据皆为正整数。

    【输入输出】

    输入:

    输入包含两行,第1行为N (N ≤10 000),表示制作的蛋糕的体积为N π;第2行为M (M ≤20),表示蛋糕的层数。

    输出:

    单行输出一个正整数S (若无解,则S =0)。

    【样例】

    在这里插入图片描述

    圆柱体积V =πR^2 H ,侧面积A '=2πRH ,底面积A =πR。

    【思路分析】

    这道题为在体积和层数一定的情况下,找到合适的半径和高度,使蛋糕表面积最小。可以采用回溯法搜索求解。

    ① 预处理

    从顶层向下计算出最小体积和面积的最小可能值。在从顶层(即第1层)到第i 层的最小体积minv [i ]成立时,第i 层的半径和高度都为i 。此时只计算侧面积,对上表面积只在底层计算一次,底层的底面积即总的上表面积。

    void init(){
    	minv[0] = mins[0] = 0;
    	for(int i = 1; i < 22 ; i++){
    		minv[i] = minv[i - 1] + i * i * i;
    		mins[i] = mins[i - 1] + 2 * i * i;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    【算法设计】

    dep指当前深度;sumv、sums分别指当前体积和、面积和;r 、h分别指当前层半径、高度。

    ① 从底层m 层向上搜,当dep=0时,搜索完成,更新最小面积。

    ② 剪枝技巧

    • 如果当前体积加上剩余上面几层的最小体积大于总体积n ,则退出;
    • 如果当前面积加上剩余上面几层的最小面积大于最小面积,则退出;
    • 如果当前面积加上剩余面积(剩余体积折算)大于最小面积,则退出。

    ③ 枚举半径i ,按递减顺序枚举dep层蛋糕半径的每一个可能值i ,第dep层的半径最小值为dep。

    • 如果dep=m ,sums=i ×i ,底面积作为外表面积的初始值(总的上表面积,以后只需计算侧面积)。
    • 计算最大高度maxh,即dep层蛋糕高度的上限,(n -sumv - minv[dep-1])表示第dep层的最大体积。
    • 枚举高度j ,按递减顺序枚举dep层蛋糕高度的每一个可能值j,第dep层的最小高度值为dep。
    • 递归搜索子状态,层次为dep-1,体积和为sumv+i ×i ×j ,面积和为sums+2×i ×j ,半径为i -1,高度为j -1,即dfs(dep - 1,sumv+i ×i ×j ,sums+2×i×j ,i -1,j -1)。

    【算法实现】

    #include
    #include
    
    using namespace std;
    
    const int N=30;
    const int inf=0x3f3f3f3f;
    int n,m,minv[N],mins[N],best;
    
    void init(){
    	
        minv[0]=mins[0]=0;
        for(int i=1;i<22;i++){
            minv[i]=minv[i-1]+i*i*i;
            mins[i]=mins[i-1]+2*i*i;
        }
    }
    
    void dfs(int dep,int sumv,int sums,int r,int h){
    	
        if(!dep){
            if(sumv==n&&sums<best) best=sums;
            return ;
        }
        if(sumv+minv[dep]>n||sums+mins[dep]>best||sums+2*(n-sumv)/r>best) 
    		return;
        for(int i=r;i>=dep;i--){
        	
            if(dep==m) sums=i*i;
            int maxh=min((n-sumv-minv[dep-1])/(i*i),h);
            
            for(int j=maxh;j>=dep;j--)
                dfs(dep-1,sumv+i*i*j,sums+2*i*j,i-1,j-1);
        }
    }
    
    int main(){
    	
        init();
        while(~scanf("%d%d",&n,&m)){
            best=inf;
            dfs(m,0,0,n,n);
            printf("%d\n",best==inf?0:best); 
        }
        
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    在这里插入图片描述

  • 相关阅读:
    Go语言中的init函数: 特点、用途和注意事项
    MySQL安装常见报错处理大全
    环境配置04:Pytorch下载安装
    二、系统知识笔记-系统架构概述
    Linux 或者 Docker 容器通过 date 设置系统时间
    零经验想跳槽转行网络安全,需要准备什么?
    vue路由-两个树形结构数据-递归处理方法
    CocosCreator-获取游戏可见宽高,真实宽高
    搭建springWeb保姆级教程
    吴恩达机器学习系列课程笔记——第十三章:聚类(Clustering)
  • 原文地址:https://blog.csdn.net/weixin_44226181/article/details/127762831