算法设计——生日蛋糕问题

news/2024/11/13 3:34:17/

jop:1190 生日蛋糕

  • 题目要求
    • 分析
    • 源代码

题目要求

要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。设从下往上数第i(1 <= i <= M)层蛋糕是半径为R[i], 高度为H[i]的圆柱。当i < M时,要求R[i]>R[i+1]且H[i]>H[i+1]。由于要在蛋糕上抹奶油,为尽可能节约经费,希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。令Q = Sπ,请编程对给出的N和M,找出蛋糕的制作方案(适当的R[i]和H[i]的值),使S最小,也就是求出蛋糕除了下底面的表面积最小是圆周率的多少倍?

除Q外,以上所有数据皆为正整数。

输入要求

输入有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。

输出要求

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

输入输出格式请参考原题页面。

要求使用递归-回溯算法,并在算法中尽可能引入尽可能多的剪枝措施。

题目链接:http://poj.org/problem?id=1190

分析

首先自下而上来建一个蛋糕。设蛋糕有M层,最下面一层半径r,高度h。
从下往上看,半径的最大值分别为r、r-1、…、r-M+1。高度的最大值为h、h-1、…、h-M+1。
同理,也有最小值,半径的最小值分别为M、M-1、…、1。高度的最小值为M、M-1、…、1。
从上往下看,设minV【i】表示从上往下的前i层的体积最小值,minA【i】表示前i层的侧面积的最小值。则有递推公式:
minV【i】=minV【i-1】+π*i的3次方;

minA【i】=minA【i-1】+2* π*i的2次方;
注意边界条件minV【0】=0,minA【0】=0。

蛋糕上需要涂奶油的表面积,正好就是蛋糕最底层的上表面积,因此可以将最底层的上表面积的值,作为蛋糕总表面积area的初始值。往后只需要累加每一层的侧面积即可。这里使用递归回溯法进行深度优先搜索。设DFS(int v,int top,int r,int h)表示搜索过程,其中:
v表示还要搭建多少体积;
top表示还要搭建的层数;
r表示自下而上搭建时,即将要搭建的这一层的半径可能的最大值;
h表示自下而上搭建时,即将要搭建的这一层的高度可能的最大值。
在搜索时,需要枚举当前搭建的这一层的半径和高度。设半径currentR∈【top,r】,高度currentH∈【top,h】。由于从下往上每一层的半径和高度都是递减的,所以currentR和currentH需要倒叙枚举。
由圆柱体侧面积公式可得,当前搭建的这一层的侧面积为2πcurrentRcurrentH。将这个值累加如总表面积area。接下来的过程,可以递归表示为DFS(v-currentRcurrentR*currentH,top-1,currentR-1,currentH-1)。

由于当前搭建的这一层的半径和高度,currentR和currentH的范围太大,解空间树分值太多,必须想办法进行剪枝。遇到下列情况必须剪枝:

  1. 当还要搭建的层数top为0,但是还要搭建的体积v不为0时;
  2. 还没搭建完所有的层,蛋糕体积已经超过了指定体积;
  3. 还要搭建的体积 v<还要搭建的层数的总体积的最小值minV【top】,那么还要搭建的体积满足不了上面top层的最小体积;
  4. 已经搭建好的部分蛋糕的面积area,加上还没搭建的蛋糕至少需要的表面积minA【top】,超过了目前已经求得的最少表面积;
  5. 由于每一层的高度和半径都必须是整数,若h<top或者r<top,表示再往上搭建蛋糕,高度或者半径无法满足条件;
  6. 需要搭建的共top层的蛋糕体积的最大值小于v,即剩下还没搭建的那部分体积,无论如何搭建都无法达到还缺少的体积v。
    最后注意:题目需要计算涂抹奶油的蛋糕的外表面的饿面积是多少π,因此计算过程中,可忽略π。

源代码

#include
#include
#include
#include
#include
using namespace std;
class Cake//定义一个解题类
{
protected:
int N;//题目要求中需要构建的蛋糕的体积
int M;//题目要求中需要构建的蛋糕的层数
int* minA;//数组,minA[i]表示共i层的蛋糕可能的最小侧面积
int* minV;//数组,minV[i]表示共共i层的蛋糕可能的最小体积
int minArea;//搜索过程中的一个最优值,也就是蛋糕涂抹的奶油面积的最小值
int area;//在搭建蛋糕过程中,已经搭建的蛋糕的表面积
int MaxVForNRH(int n,int r,int h) const;//计算在蛋糕有n层,底面最大半径r,最大高度h的情况下,能凑出来的最大体积
void DFS(int v,int top, int r, int h);//深度优先搜索+剪枝函数,还需要搭建的体积v,还需要搭建的层数top,正在搭建的那一层的半径最大值r,同层高度最大值h
void Init();//初始化
public:
void Solve();//求解整个测试用例的方法
};
//计算在蛋糕有n层,底面最大半径r,最大高度h的情况下的最大体积
int Cake::MaxVForNRH(int n,int r, int h) const
{
int v=0;
for(int i=0;i<n;i++)//从上往下的遍历每一层
{//从下往上的第i层的半径最大值为r-i,高度为h-i
v+=(r-i)(r-i)(h-i);
}
return v;
}
//初始化,将每一层的最小体积和最小侧面积算出来
void Cake::Init()
{
area=0;
minArea=INT_MAX;//涂抹奶油的最小表面积会不断递减,初始化为无穷大
minV[0]=0;minA[0]=0;//边界条件
for(int i=1;i<=M;i++)//从上到下遍历每一层
{
minV[i]=minV[i-1]+iii;//从上往下的前i层最小体积等于,前i-1层的最小体积加上,当前的体积i的三次方
minA[i]=minA[i-1]+2ii;//同上
}
}
//深度优先搜索+剪枝,注意搜索的半径要从大到小,否则超时
//v:还需要搭建的体积
//top:还需要的层数
//r:自下而上搭建时,即将要搭建的这一层的半径可能的最大值
//h:自下而上搭建时,即将要搭建的这一层的高度可能的最大值
void Cake::DFS(int v,int top,int r,int h)
{
if(top0)//需要搭建的层数为0,就是搭建完了,不需要再搭建了
{
if(v!=0)//但是需要搭建的体积还没完,不合理,剪枝
{
return;
}
else//需要搭建的体积也为0,得到一种搭建方案
{
minArea=min(minArea,area);//若是新方案中涂抹奶油的面积area小于原先最小的涂抹奶油的面积,就将area赋值给最小面积minArea
return;
}
}
//还没有搭建完层数,搭建出来的体积已经超过了题目指定体积,剪枝
if(v<=0) return;
//还没有搭建的那些层数的最小体积超过了还缺少的体积,剪枝
if(minV[top]>v) return;
//已经搭建好的蛋糕的表面积加上还没搭建的蛋糕至少需要的表面积,超过了目前求得的最小表面积,剪枝
if(area+minA[top]>=minArea) return;
//每一层的高度和半径都必须是整数,再往上搭建蛋糕的高度或者半径都无法满足条件,剪枝
if(h<top||r<top) return;
//剩下还没搭建的那些体积,无论如何构造都无法达到缺少的体积,剪枝
if(MaxVForNRH(top,r,h)<v) return;
for(int currentR=r;currentR>=top;currentR–)//枚举出底面积的半径,自下而上每一层半径递减,倒叙循环
{
if(top
M)//如果刚开始搭建,将最下层的底面积作为外表面积的初始值
{
area=currentRcurrentR;
}
for(int currentH=h;currentH>=top;currentH–)//枚举底层高度,自下而上每一层高度递减,倒叙循环
{
int flank=2
currentRcurrentH;//定义flank,计算当前搭建的这一层的侧面积
area+=flank;//累加每一层的侧面积到area中
DFS(v-currentR
currentRcurrentH,top-1,currentR-1,currentH-1);//递归搜索搭建上一层
area-=flank;//恢复area的值
}
}
}
void Cake::Solve()//求解所有测试用例的过程函数
{
while(cin>>N>>M)//读入N和M的值
{
minV=new int[M+1];minA=new int[M+1];//分配存储单元
Init();//初始化
if(minV[M]>N)//要搭建的M层蛋糕的体积超过了题目给定的体积
cout<<0<<"\n";//题目无解,输出0,换行
else
{
int maxH=(N-minV[M-1])/(M
M)+1;//定义变量,计算最底层的可能的最大高度,其中N指所有的层加起来的总体积,minV[M-1]表示从上往下前M-1层体积的最小值,(N-minV[M-1])则表示最下面那一层的最大体积;M表示最下面那一层的最小半径,(M*M)便是最下面那一层的最小面积;+1是防止不整除时向下取整
int maxR=(int)sqrt(double(N-minV[M-1])/M)+1;//同理,计算最底层的可能最大半径。/M中的M表示最下层的最小高度,sqrt表示开根
DFS(N,M,maxR,maxH);
if(minArea==INT_MAX)//意味数据不合法,没有搜索到最优值
cout<<0<<"\n";
else cout<< minArea<<"\n";
}
delete[] minA;delete[] minV;//动态释放空间
}
}
int main()
{
Cake obj;
obj.Solve();
return 0;
}


http://www.ppmy.cn/news/764406.html

相关文章

生日蛋糕的多种剪枝

题目背景 7月17日是Mr.W的生日&#xff0c;ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕&#xff0c;每层都是一个圆柱体。 设从下往上数第i(1<i<M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i<M时&#xff0c;要求Ri>Ri1且Hi>Hi1。 由于要在蛋糕上抹奶油&#xf…

CVPR 2022 | 只需2张照片就能2D变3D,这个AI脑补蜡烛吹灭过程

来源&#xff1a;量子位 2张废片啪地一合&#xff01; 错过的精彩瞬间立刻重现&#xff0c;还能从2D升到3D效果。 看&#xff0c;小男孩可爱的笑容马上跃然浮现&#xff1a; 吹灭生日蛋糕蜡烛的瞬间也被还原了出来&#xff1a; 咧嘴笑起来的过程看着也太治愈了吧~ 咱就是说&…

蛋糕序列

题目描述 安安今天的心情特别好&#xff0c;准备去买一些蛋糕犒劳一下自己&#xff0c;蛋糕店的蛋糕是排列成一行的&#xff0c;每个蛋糕有不同的高度&#xff0c;安安不想太过于麻烦&#xff0c;所以买的蛋糕一定要相邻&#xff0c;但是为了不突兀&#xff0c;这些蛋糕中的最高…

基于ResNet50实现多目标美味蛋糕图像分类

前言 大家好,我是阿光。 本专栏整理了《PyTorch深度学习项目实战100例》,内包含了各种不同的深度学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10语言环境:python3.7编译器:PyCharmPy…

【PS后期】一个蛋糕的故事

今天因为要讲解PS合成的知识&#xff0c;考虑到时间问题不能介绍一些复杂的教程&#xff0c;而且网上的图片素材过于凌乱&#xff0c;所以就用我们活动的图片去进行加工了。 我记得以前看PS教程时听过一句话&#xff1a;“PS的基础知识都会&#xff0c;但是面对一张图片该怎么去…

168. 生日蛋糕

7 月 17 日是 Mr.W 的生日&#xff0c;ACM-THU 为此要制作一个体积为 Nπ 的 M 层生日蛋糕&#xff0c;每层都是一个圆柱体。 设从下往上数第 i 层蛋糕是半径为 Ri&#xff0c;高度为 Hi 的圆柱。 当 i<M 时&#xff0c;要求 Ri>Ri1 且 Hi>Hi1。 由于要在蛋糕上抹奶…

【HTML源码--一】:登录+蛋糕+照片+烟花;生日快乐、新年快乐、表白等

基于 HTML+CSS+JavaScript 制作了一个小网页,有简单的用户登录功能,蛋糕、祝福、照片、烟花等小功能;稍加修改就可以用来表白、给好朋友送祝福、祝福新年等。 首先附上效果图: 点击免费下载查看:https://download.csdn.net/download/AnChenliang_1002/86590763 下面会附上…

Cocos2dx学习笔记:浅谈游戏内的适配方案

前言 本篇在讲什么 Cocos2dx中的适配方案 本篇适合什么 适合初学Cocos的小白 本篇需要什么 对Lua语法有简单认知 依赖Cocos2dx3.15环境 依赖Sublime Text编辑器 依赖VS 2015编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#xff0c;快速上手…