生日蛋糕(信息学奥赛一本通-T1441)

针对一个具体的数学问题——如何制作一个由多层组成的特定体积生日蛋糕,并使得蛋糕外表面的总面积最小,通过编写C++程序进行求解。该程序采用深度优先搜索算法,通过递归调用寻找符合条件的最优解。

【题目描述】

7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为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=πR2HV=πR2H
侧面积A=2πRHA=2πRH
底面积A=πR2

【源程序】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
const int MOD = 1E9+7;
const int N = 500000+5;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;

int n,m;
int minn=INF;
//step为前step层,v、s为前step层体积、面积,r、h为第step层半径、高
void dfs(int step,int v,int s,int r,int h){
    if(step==m){//层数搜索完,返回
        if(v==n)//体积为所给体积,更新最小面积
            minn=s;
        return;
    }

    if(v+(r-1)*(r-1)*(h-1)*(m-step)<n)//当前层体积与每层体积最大值之和小于n,不符合,返回
        return;
    if(v+1*1*1*(m-step)>n)//当前层体积与每层体积最小值之和大于n,不符合,返回
        return;
    if(2*(n-v)/r+s>=minn)//侧面积加上前step层面积大于最小值,不符合,返回
        return;

    for(int i=r-1;i>=m-step;i--){//上一层的半径的最小值要保证大于当前层半径的最小值
        for(int j=h-1;j>=m-step;j--){//上一层高度的最小值要保证大于当前层高度的最小值
            int area=s+2*i*j;//面积
            int volume=v+i*i*j;//体积
            if(area<minn&&volume<=n)
                dfs(step+1,volume,area,i,j);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    /*
        i为半径,j为高
        第1层为1,第2层为2,...,第m层为m,故半径最小为m,同理,高最小也是m
        根据题意,蛋糕体积V=n*pi,则半径i的平方i*i为底面积,乘以层数m即为体积
        则有不等式:m*(i*i*pi)<=n*pi,即:i*i*m<=n
        同理,对于高度j,有:i*i*j<=n
    */
    for(int i=m;i*i*m<=n;i++){
        for(int j=m;j*i*i<=n;j++){
            int flankArea=2*i*j;//侧面积
            int bottomArea=i*i;//底面积
            int area=flankArea+bottomArea;
            int volume=i*i*j;//体积
            if(area<minn)
                dfs(1,volume,area,i,j);
        }
    }
    printf("%d\n",minn);
    return 0;
}

 

### 关于信息学奥赛一本中生日相同问题的解析 在探讨信息学奥赛一本中的生日相同问题时,这类题目常涉及概率计算以及算法设计来判断或模拟特定条件下两个或多个人拥有相同生日的概率。虽然直接提到“生日相同”的具体题目未出现在给定参考资料中,但在资料中有提及一个与生日相关的复杂优化问题——即制作多层生日蛋糕的问题[^3]。 然而,在处理生日相同类问题时,一般采用的方法包括但不限于: - **暴力枚举法**:对于较小规模的数据集,可以过两重循环遍历所有人之间的组合情况,检查是否存在两个人具有相同的生日日期。 - **哈希表应用**:为了提高效率,可以利用哈希结构存储已经遇到过的生日记录。每当新加入一个人的信息时,只需查询该人的生日是否已经在哈希表内存在即可快速得出结论。 下面给出一段简单的C++代码实现用于检测一组人中是否有至少两人共享同一个生日的例子: ```cpp #include <iostream> #include <unordered_set> using namespace std; bool hasSameBirthday(const vector<int>& birthdays) { unordered_set<int> seen; for (int day : birthdays) { if (seen.find(day) != seen.end()) return true; seen.insert(day); } return false; } int main() { int n, birthday; cin >> n; vector<int> birthdays(n); for(int i=0;i<n;++i){ cin>>birthday; birthdays[i]=birthday; } cout << (hasSameBirthday(birthdays)? "Yes": "No") << endl; return 0; } ``` 此程序读取n个整数表示不同人的出生月份加天数(假设一年最多有365天),并输出是否存在重复的生日。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值