积木
本题采用深度优先搜索+剪枝可以完成。
由于本题只有20层的数据量不是很大,可以选用DFS遍历所有满足条件(下面的圆柱体的底面半径和高度都必须比上面的大)
的组合,分别并分别求出面积进行比较就行了,最后求出涂色面积最小的量。
void dfs(int m_left, int n_left,int r_last,int h_last,int now_s)
分别代表着还剩下的层数,还剩下的体积,上一层的半径,上一层的高度,现在的表面积。
剪枝 :如果剩下层数的最小体积仍然大于剩下的体积 return
如果现在的面积加上剩下的部分的最小面积仍然大于现在的假定最优解,则直接return
在求取剩下层数的最小体积的时候,假定最上面第一层半径为1,高度为1,则紧接着下一层是半径2,高度2,一次递推
则得出体积为i*i*i(pai)
在计算面积的时候要注意的就是凡是侧面积之外的面积和其实等于最下面那个圆柱体的底面积,这个很好说明的。
然后的话在计算面积的时候只用在增加一个圆柱体的时候初始化底面积再加上侧面积就行了。
在求取剩下层数最小面积的时候要注意其实就是现在的面积加上剩下的体积*2/r_last 这个很好利用几何证明的。
还有就是在每一次递归的时候注意求取上下界的问题。
半径的范围自然是上一层的半径-1到剩下的层数 一个是上边界一个是下边界
高度的范围自然是在这一层的最大体积/这一层的底面积 几何可以很容易求出
数学几何知识很重要哈在这样的题目当中。
#include<cstdio> #include<cstring> #define MAX 10000 int n,m,res; inline int cal(int floor) { int i = 0, res = 0; for(i=1;i<=floor;i++) res +=i*i*i; return res; } inline int minvol(int floor) { return cal(floor); } void dfs(int m_left, int n_left,int r_last,int h_last,int now_s) { if(n_left<minvol(m_left)) return ; if(now_s+2*n_left/r_last>res) return; if(m_left == 0) { if(n_left==0&&res>now_s) res = now_s; return; } for(int i=r_last-1;i>=m_left;i--) { if(m_left==m) now_s = i*i; int maxh = h_last-1; if(maxh>(n_left-minvol(m_left -1))/i/i) maxh=(n_left-minvol(m_left -1))/i/i; for(int j=maxh;j>=m_left;j--) dfs(m_left - 1,n_left-i*i*j,i,j,now_s+2*i*j); } } int main() { //freopen("1.txt","r",stdin); while(scanf("%d%d",&n,&m)==2) { res = MAX; dfs(m,n,100,10000,0); if(res == MAX) res = 0 ; printf("%d\n",res); } }