《算法竞赛进阶指南》0x23剪枝 POJ1190上下界搜索与剪枝
题目链接:http://poj.org/problem?id=1190
剪枝的常用思考策略:优化搜索顺序(从决策数量越少的位置开始决策)、排除冗余的等效的操作、可行性剪枝、最优性剪枝、上下界剪枝,其中在可行性剪枝方面可以利用“未来期望进行剪枝”
要充分利用不等式关系进行放缩,将不可能的状态进行剪枝,也是一个对“未来状态的估计”。
代码:
#include<iostream> #include<cstdio> #include<math.h> using namespace std; #define maxn 25 const int inf=0x3f3f3f3f; int n,m; int minv[maxn],mins[maxn]; int h[maxn],r[maxn]; int ans=inf; void dfs(int dep,int s,int v){ if(mins[dep]+s >= ans)return ; if(minv[dep]+v > n)return ; if(2*(n-v)/r[dep+1]+s >= ans) return ; if(dep==0){ if(n==v)ans=min(ans,s); return ; } //枚举上下界 for(int R=min((int)sqrt((double)n-v),r[dep+1]-1);R>=dep;R--) for(int H=min((n-v)/R/R,h[dep+1]-1);H>=dep;H--){ int t=0; if(dep==m)t=R*R;//所有的上表面都加到最后一层上 r[dep]=R; h[dep]=H; dfs(dep-1,s+2*R*H+t,v+R*R*H); } } int main(){ cin>>n>>m; for(int i=1;i<=m;i++){//计算前i层的最小面积和体积 mins[i]=mins[i-1]+2*i*i; minv[i]=minv[i-1]+i*i*i; } r[m+1]=h[m+1]=inf;//保证最后一行的时候上界无限制 dfs(m,0,0); if(ans==inf)cout<<0<<endl; else cout<<ans<<endl; }
每一个不曾起舞的日子,都是对生命的辜负。