裸的搜索题,就说剪枝(注:nw->noww->当前,res->rest->剩余):
1.想达到$Nπ$的体积,那么半径一开始最多也就$sqrt(n)$了,再大就超了。。。
2.可以预处理$minv[i]$表示还剩$i$层时最少还要放多少的体积,当当前体积$+minv[res]>n$时剪掉
3.每次枚举高度时从$n-V_{nw}-minv[res-1]$枚举,这是这一层高的高度,再高就超了。。。
4.上面的那些都是小弟弟,这个是最强的(雾
∵$S_{res}=2*sumlimits_{i=nw}^{m}r_i*h_i$,$V_{res}=sumlimits_{i=nw}^{m}{r_i}^2*h_i$
∴$S_{res}=sumlimits_{i=nw}^{m}frac{2*V_{i}}{r_i}$
∴$S_{res}>=frac{2*V_{res}}{r_{nw}}$
加了之后跑的飞起=。=
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int minv[20],mins[20]; 7 int n,m,s,maxx; 8 void prework() 9 { 10 minv[1]=mins[1]=1; 11 for(int i=2;i<=16;i++) 12 minv[i]=minv[i-1]+i*i*i,mins[i]+=i*i; 13 } 14 inline int mini(int a,int b) 15 { 16 return a<b?a:b; 17 } 18 void DFS(int lasr,int lash,int res,int noww,int area) 19 { 20 if(!res) {if(noww==n&&s>area) s=area; return ;} 21 if(noww+minv[res]>n) return ; 22 if(res!=m&&2*(n-noww)/lasr>=s-area) return ; 23 for(int i=lasr-1;i>=res;i--) 24 { 25 int maxh=mini(n-noww-minv[res-1],lash-1); 26 for(int j=maxh;j>=res;j--) 27 DFS(i,j,res-1,noww+i*i*j,area+2*i*j+(res==m)*i*i); 28 } 29 } 30 int main () 31 { 32 scanf("%d%d",&n,&m); 33 maxx=sqrt(n)+2,s=1e9; 34 prework(),DFS(maxx,maxx,m,0,0); 35 printf("%d",(s==1e9)?0:s); 36 return 0; 37 }