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;
}

posted @ 2019-05-30 07:21  风浔凌  阅读(145)  评论(0编辑  收藏  举报