P1731 [NOI1999] 生日蛋糕

原题链接

考察:dfs+剪枝

思路:

        首先明确暴力的思路,我们枚举每一层的r与h,求出所有满足V=N的表面积(dfs本质是暴力,我们所要做的就是剪枝).接下来考虑一些剪枝:

  1. 搜索顺序的剪枝.当我们当前枚举的体积很大时,剩下能找的r、h体积就必须尽量小,这样可以优化搜索顺序.
  2. 最优性剪枝:当s>=ans,直接return
  3. 等效冗余:这里不是组合型枚举,貌似没有
  4. 可行性剪枝:预处理每层最小体积.当当前v+a[i]>n return,同理表面积.既然考虑了最小体积,也要考虑最大体积,这涉及到r与h的上界与下界.很明显i<=ri<=min(sqrt(n-v),ri+1) 假设高度为1.i<=hi<=min((n-v)/r/r,ri+1).
  5. 还有一个比较难想到的剪枝:根据当前体积预估表面积. (n-v)/ri+1*2+si~m
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <cmath>
 5 using namespace std;
 6 const int N = 25,INF = 0x3f3f3f3f;
 7 int n,m,a[N],ans = INF,b[N];
 8 void dfs(int k,int v,int s,int h,int r)
 9 {//层数 体积 表面积 高度 半径 
10     if(v+a[k]>n) return;
11     if(s+b[k]>ans) return;
12     if(s>=ans) return;
13     if(r&&2*(n-v)/r+s>=ans) return;
14     if(!k)
15     {
16         if(v==n) ans = s;
17         return;
18     }
19     for(int i=min(r,(int)sqrt(n-v));i>=k;i--)
20     {
21         if(k==m) s = i*i;
22         for(int j=min(h,(n-v)/i/i);j>=k;j--)
23           dfs(k-1,v+i*i*j,s+2*i*j,j-1,i-1);
24     }
25 }
26 int main() 
27 {
28     scanf("%d%d",&n,&m);
29     for(int i=1;i<=m+1;i++)
30     {
31         a[i] = i*i*i+a[i-1];//第i层用的最小体积.
32         b[i] = 2*i*i+b[i-1];
33     }
34     dfs(m,0,0,n,n);
35     printf("%d\n",ans==INF?0:ans);
36     return 0; 
37 }

 

posted @ 2021-03-09 21:38  acmloser  阅读(72)  评论(0编辑  收藏  举报