洛谷 P1731 生日蛋糕

题目背景

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<=20000),表示待制作的蛋糕的体积为Nπ;第二行为M(M<=15),表示蛋糕的层数为M。

 

输出格式:

 

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

 

输入输出样例

输入样例#1:
100
2
输出样例#1:
68
思路:搜索+剪枝。
错因:一开始只加了可行性剪枝,拿到了60分,后来才知道还有最优化剪枝。
60分的可行性剪枝:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,ans=0x7f7f7f7f,sal,val,use[16];
struct nond{
    int r,h;
}v[16];
void dfs(int now){
    if(val>n)    return ;
    if(sal+v[1].r*v[1].r>=ans)    return ;
    if(now>m&&val<n)    return ;
    if(now>m&&val==n){
        ans=sal+v[1].r*v[1].r;
        return ;
    }
    for(int i=v[now-1].h-1;i>=m-now+1;i--){
        for(int j=m-now+1;j<v[now-1].r;j++){
            v[now].h=i;
            v[now].r=j;
            val+=j*j*i;
            sal+=2*j*i;
            dfs(now+1);
            v[now].h=0;
            v[now].r=0;
            val-=j*j*i;
            sal-=2*j*i;
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    v[0].h=n/(m*m)+2;
    v[0].r=sqrt(n/m)+2;
    dfs(1);
    cout<<ans;
}
AC的最优化剪枝:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int nn,m,n,ans=0x7f7f7f7f;
int ss[21],sv[21];
void dfs(int t,int sal,int val,int lr,int lh){
    int maxh,i;
    if(t==0){
        if(val==n)    ans=min(ans,sal);
        return;
    }
    if(val+sv[t]>n) return;
    if(sal+ss[t]>ans) return; 
    if(sal+2*(n-val)/lr>ans) return;//第三重剪枝:假设剩余所有的体积都用来做下一层那么此时下一层的体积是最大,而半径会最大,从而表面积最小 
    for(int r=lr-1;r>=t;r--){ 
        if(t==m) sal=r*r;
        maxh=min((n-val-sv[t-1])/(r*r),lh-1);
        for(int h=maxh;h>=t;h--)
              dfs(t-1,sal+2*r*h,val+r*r*h,r,h);
    }
}
int main(){
    //freopen("cake.in","r",stdin);
    //freopen("cake.out","w",stdout);
    int i;
    cin>>n>>m;
    for(i=1;i<=m;++i){ 
        ss[i]=2*i*i+ss[i-1];
        sv[i]=i*i*i+sv[i-1];
    }
    dfs(m,0,0,sqrt(n),n);
    if(ans==0x7f7f7f7f)    cout<<"0";
    else cout<<ans; 
    return 0;    
}

 

 
posted @ 2017-09-02 17:51  一蓑烟雨任生平  阅读(205)  评论(0编辑  收藏  举报