P1731 [NOI1999] 生日蛋糕
考察:dfs+剪枝
思路:
首先明确暴力的思路,我们枚举每一层的r与h,求出所有满足V=N的表面积(dfs本质是暴力,我们所要做的就是剪枝).接下来考虑一些剪枝:
- 搜索顺序的剪枝.当我们当前枚举的体积很大时,剩下能找的r、h体积就必须尽量小,这样可以优化搜索顺序.
- 最优性剪枝:当s>=ans,直接return
- 等效冗余:这里不是组合型枚举,貌似没有
- 可行性剪枝:预处理每层最小体积.当当前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).
- 还有一个比较难想到的剪枝:根据当前体积预估表面积. (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 }