莫欺少年穷,修魔之旅在这开始—>算法提高课题解
剪枝与优化
1. 优化搜索顺序
2. 排除等效冗余
3. 可行性剪枝
4. 最优性剪枝
5. 记忆化搜索(dp)
思路:
1. 优化搜索顺序:从大到小枚举
2. 可行性剪枝:v + minv[u] <= n;s + 2 * (n - v) / R[u + 1] < ans;
3. 最优性剪枝:s + mins[u] < ans;
4. R 的范围:[u, min(R[u + 1] - 1, sqrt(n - v))]
5. H 的范围:[u, min(H[u + 1] - 1, (n - v) / (r ^ 2))]
#include<bits/stdc++.h>
using namespace std;
const int N = 25, INF = 1e9;
int n,m;
int minv[N],mins[N];
int R[N],H[N];
int ans=INF;
//从下往上放
void dfs(int u,int v,int s)
{
//当前体积+接下来的体积>n
if(v+minv[u]>n) return;
//当前面积+接下来的面积>m
if(s+mins[u]>=ans) return;
//放缩可得
if(s+2*(n-v)/R[u+1]>=ans) return;
if(!u)
{
if(v==n) ans=s;
return;
}
//从范围里面循环
for(int r=min(R[u+1]-1,(int)sqrt(n-v));r>=u;r--)
for(int h=min(H[u+1]-1,(n-v)/r/r);h>=u;h--)
{
int t=0;
if(u==m) t=r*r;
R[u]=r,H[u]=h;
dfs(u-1,v+r*r*h,s+2*r*h+t);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
minv[i]=minv[i-1]+i*i*i;
mins[i]=mins[i-1]+2*i*i;
}
R[m+1]=H[m+1]=INF;
dfs(m,0,0);
cout<<(ans==INF?0:ans)<<endl;
return 0;
}