本地的重要启示:
在接下来对每一个子问题进行搜索前可以先获得该子问题的搜索目标的极限,通过该极限可以判断对该子问题搜索出的解能否比当前最优解更优;或对该子问题搜索出的搜索目标能否满足要求,如果不能,就没必要了搜下去了,直接跳过对该子问题的搜索。该剪枝可以有效减小对某一子问题的搜索深度。
这道题都说很经典,而我这种小白水平和感悟都不够,因此就不讲了,放上学习过程中对我有帮助的资源,供大家学习参考
本题的最优化剪枝与可行性剪枝:
下面是按gw老师的思路写的代码,看完别走,后面还有更好的:
#include <iostream> #include <cstring> #include <vector> #include <cmath> using namespace std; #define maxn 102 const int inf=1<<30; int mina[30]; //仅侧面 int minv[30]; int maxh,maxr; int minarea=inf; int n0; int area=0; int last_maxv(int n,int mr,int mh){ int maxv1=0; for(int i=0;i<n;i++){ maxv1+=(mr-i)*(mr-i)*(mh-i); // maxv2+=(n-i)*(n-i)*(mh-1); } return maxv1; } void dfs(int v,int n,int mr,int mh){ if(n==0){ if(v) return; else{ minarea=min(minarea,area); return; } } if(v<=0) return; if(v<minv[n]) return; if(mr<n || mh<n) return; if((area+mina[n])>=minarea) return; if( last_maxv(n,mr,mh)<v) return; for(int r=mr;r>=n;r--){ if(n==n0) area=r*r; for(int h=mh;h>=n;h--){ area+=2*r*h; dfs(v-r*r*h,n-1,r-1,h-1); area-=2*r*h; } } } int main() { // freopen("in.txt","r",stdin); minv[0]=0;mina[0]=0; int v; cin>>v>>n0; for(int i=1;i<=n0;i++){ mina[i]=2*i*i+mina[i-1]; minv[i]=i*i*i+minv[i-1]; } if(v<minv[n0]) { cout<<0<<endl; return 0; } maxh=(v-minv[n0-1])/(n0*n0)+1; maxr=sqrt(double(v-minv[n0-1])/n0)+1; //用double防止小数点后面的丢失 // cout<<maxh<<' '<<maxr; dfs(v,n0,maxr,maxh); // cout<<"Loved"<<endl; if(minarea==1<<area) cout<<0<<endl; else cout<<minarea<<endl; return 0; }
提交之后发现我的代码要跑47ms,但是很多人的只需要0ms,而且内存占用更小,于是找到一份0ms的来学习一下:
这个剪枝讲的不错,代码注释清楚:链接