這道題給你那麼少的東西,就是要你爆搜了。數組
先注意一下,否則後面的作不了了,直接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; }