原始思路(黑色)
正解(highlighter)
从几个角度考虑
- 优化搜索顺序:
本题本来就有顺序
对,的确要从下往上 - 排除等效冗余:
无
无 - 可行性剪枝:
若往上放的蛋糕体积尽可能大也不符合要求直接return
除此之外还要注意:
1.若放上的体积最小也超出return 2.h和r的取值范围要大于从上往下数的层数(否则后面无法安排)3. h和r要小于上一层且小于sqrt(n-v),v是已经摆出的体积. - 最优性剪枝:
若目前的表面积超出已求得最优return
更好的是
1.当前加上剩下层数可组成最小表面积大于最优return
2.V=h×r×r,S_侧=2×r×h,所以2(n-v)/r[x]+s小于接下来的面积(r一层比一层小)所以这个值若大于已找到的最小表面积return - 记忆化:
无
无
代码(剪枝相关处加了斜线或注释)
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,m;
int v[20],s[20];
int h[20],r[20];
int ans=0x7f7f7f7f;
void dfs(int x,int vn,int sn)
{
if(vn+v[x]>n)return;//
if(sn+s[x]+r[m]*r[m]>=ans)return;//
if(x==0)
{
if(vn==n)ans=min(ans,sn+r[m]*r[m]);
return;
}
if(vn+h[x+1]*r[x+1]*r[x+1]*x<n)return;//
for(int i=min(r[x+1]-1,(int)sqrt(float(n-vn)));i>=x;--i)
//for循环从大到小是为了少算几次min(),增快速度,很重要
{
for(int j=min(h[x+1]-1,(n-vn)/(i*i));j>=x;--j)
{
r[x]=i,h[x]=j;
if(2*(n-vn)/r[x]+sn<=ans)//
dfs(x-1,vn+r[x]*r[x]*h[x],sn+2*r[x]*h[x]);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
v[i]=v[i-1]+i*i*i;
s[i]=s[i-1]+2*i*i;
}
r[m+1]=100;
h[m+1]=100;
dfs(m,0,0);
if(ans==0x7f7f7f7f)printf("0\n");
else printf("%d\n",ans);
return 0;
}