泰国佛塔

描述

泰囧,大家应该都看过。不知道大家有没有注意到宝宝虔诚祈福的寺庙里的金灿灿的佛塔。      

众所周知,泰国佛塔外面是贴金的,而且金箔过一段时间需要修补。泰国经济自上世纪末就不景气,贴金的开支对于寺庙来说也是个比较大的负担。          

这里请同学来帮助寺庙设计下佛塔的模型,以使佛塔的外表面(最下层的下底面除外)的面积最小。从而节省金箔开支。      

这里抽象佛塔形状为,一层层的圆柱体,自底向上直径递减。制作一个体积为Nπ的M层佛塔。设从下往上数第i(1 <= i <= M)层佛塔是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri> Ri+1且Hi> Hi+1。令外表面面积为Q=Sπ。      

请编程,对于给出的N和M,找出佛塔的制作方案(适当的Ri和Hi的值),使S最小。(除Q外,以上所有数据皆为正整数)

输入
包括若干行。每行包括两个整数N(N <= 10000)、M(M <= 20),代表一组测试数据。分别表示待建造的佛塔的体积为Nπ,和佛塔的层数为M。
输出
对于每组测试数据,输出占一行:一个正整数S(若无解则S = 0)。
样例输入
100 2
27 15
样例输出
68
0

感谢周洋师弟的帮助。


#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

/*
考虑用m层佛塔去凑n体积,考虑几种剪枝;
*/

const int MAX_N = 10010;
int min_v[MAX_N],min_s[MAX_N];//min_x[m]表示m层佛塔所具有的最小的体积/侧面积;
int MAX_NRH_Store[25][25][25];//储存MAX_V_NRH函数的返回值;
int mins = 1<<30;//记录最小侧面积;
int N,M;//n为总体积,m为总层数

int MAX_V_NRH(int m,int r,int h)
{//计算底层半径为r,底层高度为h的n层佛塔的最大体积;
    if(MAX_NRH_Store[m][r][h])//省去重复计算;
        return MAX_NRH_Store[m][r][h];
    int v = 0;
    for(int i = 0;i < m;i++){
        v += (r-i)*(r-i)*(h-i);
    }
    return v;
}

int dfs(int n,int m,int s,int r,int h)
{//深搜函数,用m层佛塔凑出体积n,底层半径r,底层高度h,当时侧面积之和为s;
    if(m==0){//层数用完,若剩余体积为0,完成,返回0;
        if(n==0)
            mins = min(s,mins);
        return 0;
    }
    if(min_v[m] > n || min_s[m] + s >= mins){//体积或侧面积超出;
        return 0;
    }
    if(MAX_V_NRH(m ,r ,h) < n){//剩下m层凑不出体积n;
        return 1;
    }
    //剪枝完毕,开始通过循环进行求解
    for(int i = r;i >= m;i--){
        for(int j = h;j >= m;j--){
            if(m == M)//剩余层数为全部M层,需考虑底面积;
            {
                if(dfs(n - i * i * j,m - 1,s + i * i + 2 * i * j,i - 1,j - 1))
                    break;//跳出本层循环;
            }
            else
            {
                if(dfs(n - i * i *j,m - 1,s + 2 * i * j,i - 1,j - 1))
                    break;
            }
        }
    }
    return 0;
}

int main(){
    memset(MAX_NRH_Store,0,sizeof(MAX_NRH_Store));
    while(cin >> N >> M){
        mins = 1<<30;
        for(int i = 0;i < M; i++){
            //无需初始化,全局变量声明后自动赋值为0;
            min_v[i+1] = min_v[i] + (i+1)*(i+1)*(i+1);
            min_s[i+1] = min_s[i] + 2*(i+1)*(i+1);
        }
        int max_r = sqrt(double(N - min_v[M - 1])/M) + 1;
        int max_h = (N - min_v[M - 1])/(M * M) + 1;

        dfs(N, M, 0, max_r, max_h);

        if(mins == 1 << 30)
            cout<<0<<endl;
        else
            cout<<mins<<endl;
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值