生日蛋糕
赤果果的搜索题。
恩,好题。
对于剪枝来说,我们可以使用最优情况进行剪枝,即是:使用最优情况+现在的情况与得到的答案进行比较
类似于估价函数的简单实现
然后对于这个题,我们可以寻找体积与面积之间的联系,利用不等式进行剪枝
$S_{\text{剩余}}=\sum^{m}_{i=\text{剩余层数}} ~~~~~R_i \cdot 2 \cdot H_i $
\(V_{\text{剩余}}=\sum^{m}_{i=\text{剩余层数}}~~~~~R_I^2 \cdot H_i\)
对于\(V_{\text{剩余}}\),有\(\frac{V_{\text{剩余}} \cdot 2}{R_{\text{当前层}}} <= S_{\text{剩余}}\)
所以,我们可以根据上述式子进行剪枝
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using std::min;
const int M=16;
int n,m;
int r[M],S[M],V[M],h[M];
int ans=0x7fffffff;
void dfs(int Vol,int sum,int now,int R,int H)//Vol:当前体积,sum:当前面积,now当前层数(自上而下),R:当层的最大半径,H同理
{
if(now==0)//终止条件
{
if(Vol==n)
ans=min(ans,sum);
return ;
}
if(sum+S[now]>=ans) return ;//最优情况剪枝
if(Vol+V[now]>n) return ;//最优情况剪枝
if(2*(n-Vol)/R+sum>=ans) return ;//根据两者之间的关系剪枝
for(int i=R;i>=r[now];i--)
{
if(now==m) sum=i*i;//如果是底层,加上顶部面积
int NxtH=min(H,(n-Vol-V[now-1])/(i*i));//根据上面蛋糕的最优情况,计算当前层的最高的高度
for(int j=NxtH;j>=h[now];j--)//枚举
dfs(Vol+i*i*j,sum+i*2*j,now-1,i-1,j-1);//emmmm
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
r[i]=i,h[i]=i;
for(int i=1;i<=m;i++)
S[i]=S[i-1]+r[i]*2*h[i];
for(int i=1;i<=m;i++)
V[i]=V[i-1]+r[i]*r[i]*h[i];
dfs(0,0,m,28,28);
if(ans==0x7fffffff) ans=0;
printf("%d",ans);
}