洛谷 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; }
细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。
雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。