搜索剪枝,
1.枚舉上下界:
先$Rsubset$$(dep,min(lfloorsqrt{n-v} floor,lastr-1))$
后$Hsubset$$(dep,min((n-v)/R^{2},lasth-1))$
由$pi R^{2}H=pi(n-v)$可以推出來,R那裡沒有除H是因為H最小為1
2.優化搜索順序:倒序以減小枚舉規模,應該會更快
3.不太複雜的預估(可行性剪枝
預處理出$1$~$dep-1$層的最小體積前綴和,最小側面積前綴和,每次加一下和$n、ans$比較
4.比較複雜的預估(最優性剪枝
單獨判斷s和v還不太夠,他們之間也有一些約束關係,
$1$~$dep-1$層的體積可表示為$n-v=sum_{k=1}^{dep-1} h[k]*r[k]^{2}$
表面積可表示為$2sum_{k=1}^{dep-1} h[k]*r[k]$
因為
$2sum_{k=1}^{dep-1} h[k]*r[k]=frac{2}{r[dep]} * sum_{k=1}^{dep-1} h[k]*r[k]*r[dep] geqslant frac{2}{r[dep]} * sum_{k=1}^{dep-1} * h[k] * r[k]^{2} geqslant frac{2(n-v)}{r[dep]}$
所以當$frac{2(n-v)}{r[dep]}+s$大於答案時剪枝
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int maxn=20009; int n,m,ans=999999999; int smv[maxn],sms[maxn];//最小體積和,最小側面積和 void dfs(int dep,int s,int v,int lstr,int lsth){ if(dep==0){ if(v==n)ans=min(ans,s);return; } if(v+smv[dep]>n)return; if(s+sms[dep]>ans)return; if(s+2*(n-v)/lstr>ans)return; for(int r=min((int)sqrt(n-v),lstr-1);r>=dep;r--){ if(dep==m)s=r*r; for(int h=min((n-v)/(r*r),lsth-1);h>=dep;h--){ dfs(dep-1,s+2*r*h,v+r*r*h,r,h); } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ sms[i]=sms[i-1]+2*i*i; smv[i]=smv[i-1]+i*i*i; } dfs(m,0,0,sqrt(n),n); if(ans==999999999)printf("0"); else printf("%d",ans); }
($LaTeX$首使用