这道题给你那么少的东西,就是要你爆搜了。数组
先注意一下,否则后面的作不了了,直接WA掉。优化
他的意思是:spa
咱们但愿蛋糕外表面(最下一层的下底面除外)的面积Q最小。code
因此除了最下一层的下表面以外的全部蛋糕表面积都要算进答案。blog
能够发现,上面的圆柱体能够按下去,因此全部的上表面等于最下的圆柱底面积。再加上全部的侧面积就是答案。rem
千万不要想错了!io
翻题解发现:可使用数组存储咱们建这个多边形的半径和高,方便剪枝。class
咱们必须从下往上搜,由于上面的高度和半径都必定小于下面的。原理
搜索就是个两个循环嵌套,可是能够优化。搜索
在下面的dfs中,咱们只添加侧面积,最后的底面圆柱底面积等结算的时候再加上就能够了。
搜到最上面,必须知足剩下的体积为0,再判断答案可不能够更新。
这就是爆搜思路了。
可是你会赤裸裸地TLE。
你须要剪枝!
剩下的体积确定不为0,这不合法,剪枝。
当前体积 + 当层体积 * 层数 若是还小于整体积,剪枝。
当前答案 + 1 * 层数 + 底面圆柱底面积 若是还大于等于答案,剪枝。
刚开始枚举的时候,能够从$n$开三次方开始搜,不过为了方便,sqrt便可,问题不大。
正向枚举半径,逆向枚举高度。原理看讨论区。
循环中的下界能够不是1,是当前的层数。
加上这些再开$O_2$就能过了吧。。。
代码:
#include<cstdio> #include<cmath> const int maxn = 30, INF = 0x3f3f3f3f; int r[maxn], h[maxn]; int n, m, ans = INF; void dfs(int t, int remain, int res, int layer) { if(remain < 0) return; if(res >= ans) return; if(t > m + 1) return; if(layer == 0 && t == m + 1) { if(remain == 0 && res + r[1] * r[1] < ans) ans = res + r[1] * r[1]; return; } if(remain - r[t - 1] * r[t - 1] * h[t - 1] * layer > 0) return; if(res + layer + r[1] * r[1] >= ans) return; for(register int i = r[t - 1] - 1; i >= layer; i--) { for(register int j = h[t - 1] - 1; j >= layer; j--) { r[t] = i; h[t] = j; if(remain - i * i * j >= 0) dfs(t + 1, remain - i * i * j, res + 2 * i * j, layer - 1); r[t] = 0; h[t] = 0; } } } int main() { scanf("%d%d", &n, &m); r[0] = h[0] = (int)(sqrt(n)); //printf("%d\n", ans); dfs(1, n, 0, m); if(ans == INF) printf("0\n"); else printf("%d\n", ans); return 0; }