生日蛋糕c++
POJ - 1190 编程
题目:ide
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外,以上全部数据皆为正整数) spa
Input.net
有两行,第一行为N(N <= 10000),表示待制做的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。code
Outputblog
仅一行,是一个正整数S(若无解则S = 0)。get
Sample Input数学
100it
2
Sample Output
68
Hint
圆柱公式
体积V = πR 2H
侧面积A' = 2πRH
底面积A = πR 2
思路:
很容易就能够知道是按照层数进行dfs。当知足层数条件以及体积条件时,找到最小的答案就能够输出了。只是为何想把这题目写出来呢?由于这题目对时间的要求看似宽松,实则让人想吐血。写出来的dfs须要大量地剪枝,尤为是hnust的oj上对剪枝的要求简直是……太严格了。主要是须要剪枝的有三大类:
1) n+minv[m-1]>N 当前已经计算出来的蛋糕的体积,加上剩下的层数中可能制造出的最少的蛋糕的体积的结果若是大于n,剪掉。
2) sum+mins[m-1]>ans 当前已经计算出来的蛋糕的表面积,加上剩下层数中可能制造出的最少的蛋糕的表面积的结果若是大于以前计算出来的结果(ans)时,剪掉。
3) sum+2*(N-n)/r>=ans 数学公式推导:n-sumv既所剩体积记做dv 还须要的表面积为s
s=2*ri*hi+2*r(i-1)*h(i-1)+... >=2*ri*hi*ri/r+2*r(i-1)*h(i-1)*r(i-1)/r+...
=2*dv/r(i从M-1取,r为当前半径 ri/r<1)
因此获得还须要的最小表面积s=2*(n-sum)/r,若是最小的s和已经搜索过的表面积sum依然比ans大 就不用继续搜索了
若是仍是时间超限的话(例如hnust里提供的数据)就须要第四次剪枝了。
4)当前计算出来的体积,加上可能的最大的蛋糕体积的结果小于n,剪掉。这个是参考了大佬的思路,就不贴出来了,都找获得
AC代码:
#include<bits/stdc++.h> using namespace std; int h,r,N,M,mins[25],minv[25]; const int inf=1<<30; int ans=inf; int sum=0; void dfs(int r,int h,int n,int m,int sum) { if(m==0) { if(n==N&&sum<ans) { ans=sum;//cout<<r<<" "<<h<<endl; } return; } if(n+minv[m-1]>N||sum+mins[m-1]>ans||sum+2*(N-n)/r>=ans) return; for(int i=r-1; i>=m; i--) { int jl=i*i; if(m==M) sum=jl; int maxh=((N-n-minv[m-1])/(i*i)<h-1)? (N-n-minv[m-1])/(i*i):h-1; for(int j=maxh; j>=m; j--) { dfs(i,j,n+jl*j,m-1,sum+2*i*j); } } } int main() { minv[0]=0; mins[0]=0; for(int i=1; i<=20; i++) //从顶层向下计算出最小体积和表面积的可能值 { //从顶层(即第一层)到第i层的最小体积minv[i]成立时第j层的半径和高度都是j minv[i]=minv[i-1]+i*i*i; mins[i]=mins[i-1]+2*i*i; } while(scanf("%d %d",&N,&M)==2) { ans=inf; int rmax=(int)sqrt((double)N); //rmax初始半径 底层半径 最大值为sqrt(n) int hmax=N; //hmax初始高度 高度最大为 n dfs(rmax,hmax,0,M,0); if(ans==inf) cout<<0<<endl; else cout<<ans<<endl; } return 0; }