NOI1999 生日蛋糕
题目链接:戳我
剪枝的搜索题
我们考虑从大到小枚举每一层
- 如果当前的体积大于总体积 return
- 枚举下一层的时候是[还剩下的层数,上一层的-1]
- 如果当前的面积加上后面有可能的最大面积还是比ans大,return
- 如果当前的体积加上后面有可能的最小体积还是比n小,return
- 面积计算直接带入参数,不要重开函数计算
- h,r从\(\sqrt n\)开始枚举
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctime>
#define MAXN 20
using namespace std;
int n,m;
int r[MAXN],h[MAXN];
int ans=2147483647;
inline int sqr(double x){return x*x;}
inline int calc()
{
// for(int i=1;i<=m;i++) printf("i=%d r=%d h=%d\n",i,r[i],h[i]);
int cur_ans=0;
for(int i=1;i<=m;i++) cur_ans+=r[i]*h[i];
return cur_ans;
}
inline void search(int pos,int now,int cans)
{
if(cans+(m-pos+1)+r[1]*r[1]>ans&&pos<=m) return;//面积
if(now+(m-pos+1)*sqr(r[pos-1])*(h[pos-1])<n&&pos<=m) return;//体积
if(pos>m)
{
if(now==n)
{
cans+=r[1]*r[1];
ans=min(ans,cans);
}
return;
}
for(int i=r[pos-1]-1;i>=m-pos+1;i--)
{
for(int j=h[pos-1]-1;j>=m-pos+1;j--)
{
if(now+sqr(i)*j<=n)
{
r[pos]=i;
h[pos]=j;
search(pos+1,now+sqr(i)*j,cans+2*i*j);
r[pos]=0,h[pos]=0;
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
// freopen("ce.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
h[0]=(int)sqrt(n);
r[0]=(int)sqrt(n);
search(1,0,0);
printf("%d\n",ans);
// cout<<(double)clock()/CLOCKS_PER_SEC<<endl;
return 0;
}