洛谷P1731:https://www.luogu.org/problemnew/show/P1731ios
思路
三重剪枝ide
- 當前表面積+下一層表面積若是超過最優值就退出
- 當前體積+下一層體積若是超過整體積就退出
- 假設剩餘全部的體積都用來作下一層那麼此時下一層的體積是最大 而半徑會最大 從而表面積最小(定理:當體積必定時 半徑越大 表面積越小)
每次枚舉半徑和高時 是從下一層的半徑和高到還剩下的層數 由於每層都要比下面大1spa
代碼


#include<iostream> #include<cmath> using namespace std; #define maxn 30 #define inf 2147483647 int n,m,ans=inf; int v[maxn],s[maxn]; void dfs(int now,int s1,int v1,int r,int h)//now爲當前層數 s1爲已經有的表面積 v1爲已經有的體積 //r爲當前半徑 h爲當前高度 { if(now==0)//若是到頂層 { if(v1==n&&s1<ans)//且體積知足題目要求 而且表面積小於原來的最優 ans=s1; return; } if(s1+s[now]>ans) return;//當前表面積+下一層表面積若是超過最優值就退出 if(v1+v[now]>n) return;//當前體積+下一層體積若是超過整體積就退出 if(s1+2*(n-v1)/r>ans) return;//假設剩餘全部的體積都用來作下一層那麼此時下一層的體積是最大 //而半徑會最大,從而表面積最小 for(int i=r-1;i>=now;i--)//從下一層最小半徑開始枚舉尋找合適的半徑 { if(now==m) s1=i*i;//若是是底層 表面積爲「頂面 」 int h1=min(h-1,(n-v1-v[now-1])/(i*i));//整體積-已用體積-下一層體積除底面積爲高與下一層最大高度比較 for(int j=h1;j>=now;j--) { dfs(now-1,s1+2*i*j,v1+i*i*j,i,j); } } } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { v[i]=v[i-1]+i*i*i;//前i層+自身的最大致積 s[i]=s[i-1]+2*i*i;//i層+自身的最大表面積 } dfs(m,0,0,sqrt(n),n); if(ans==inf) cout<<0; else cout<<ans; }