生日蛋糕 剪枝
体积固定为 n π 、固定m层,每一层都是一个圆柱体,
从上往下,圆柱的半径、高度二者必须都是递减的,
也就是 r[i+1]>r[i] 、 h[i+1]>h[i]
找出一个方案使得整个圆柱的外表面积最小(除了最底下那一层的下低面)
最后的答案除π
# 题解
状态包含的状态有当前的层数、已经确定的体积、已经确定的面积
题目中对最后的答案除圆周率,所以可以直接忽略
剪枝:
1)优化搜索顺序 蛋糕从底向上搜索
2)上下界剪枝 当前的半径一定小于上一层,最大是上一层-1 或 sqrt(n-v)
当前的高度也一定小于上一层,最大是上一层-1 或 (n-v)/R^2
高度中有一个需要根据R求出所以先枚举R
R ∈ [ deep , min( |sqrt(n-v)|, r[deep+1]-1 ) ]
H ∈[ deep , min( (n - v) / R^2 , h[deep +1) -1 ]
3)可行性剪枝 预处理从上往下前 i 层的最小体积和侧面积,1~i 层的高度和半径最小为1,2,3,……,i,如果当前的体积加上前 i 层的最小体积>n直接回溯
4)最优性剪枝
1. 若 i 层表面积加上前面已经得到的侧面积大于搜索到的答案,剪枝
2. 1~u层的体积 =
1~u层的面积为
因为 可以求得,所以放缩成可以用 表示的不等式
当 大于已搜到的答案的时候,剪枝
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=25;
4 int n,m;
5 int R[N],H[N];
6 int minv[N],mins[N];
7 int ans=INT_MAX;
8 void dfs(int u,int v,int s){
9 if(v+minv[u] > n) return;
10 if(s+mins[u] >= ans) return;
11 if(2*(n-v)/R[u+1]+s>=ans) return;//关键最优性剪枝
12
13 if(!u){
14 if(v==n) ans=s;//剪枝将所有大的都剪掉了剩下的一定是能够更新最小值的
15 return;
16 }
17 for(int r = min( R[u+1]-1,(int)sqrt(n-v)); r >= u; r --)//优化搜索顺序,先从大的r开始,h由r确定最大
18 for(int h = min( H[u+1] - 1, (n - v) / r / r); h >= u; h--){
19 int t=0;
20 if(u==m)
21 t=r*r;
22 R[u]=r;
23 H[u]=h;
24 dfs(u-1,v+r*r*h,s+t+2*r*h);
25 }
26 }
27 int main(){
28 cin>>n>>m;
29
30 for(int i=1;i<=m;i++){
31 minv[i]=i*i*i;
32 mins[i]=2*i*i;
33 }
34 R[m+1]=H[m+1]=INT_MAX;
35
36 dfs(m,0,0);
37 cout<<ans<<endl;
38 }