分蛋糕
题意:中文提不说了...题目类型:DFS
题解:如果一开始我单独看到这道题,肯定不会朝搜索方向想。。。这里要积累一下思路。因为M,N的数据范围给定,且数据范围满足递减的要求,因此解空间有限,应该有搜索的想法,看看数据好像可以搜,考验剪枝水平;
爆搜方法,就是每次枚举100以内的半径,1000以内的高,搜索m层(m<=20),如果体积为刚好就存下结果,每一次取最小值;
剪枝部分,如果当前的圆柱半径与高度能够成的最大体积小于剩余体积,就结束;如果当前的面积大于之前搜到的最小面积,就结束;最后一个剪枝,不容易想到,如果到第k层时剩下第k到第M层的面积 2*Ri*Hi>2*Ri*Ri*Hi/Rk=2*Vi, 全部加起来就是 2*leftV, 所以 A+2*leftV>min 可以剪枝;
Code:
#include <iostream>
#include <cstdio>
#include<cstring>
#include<algorithm>
#include <string>
#include <queue>
#include <map>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int N,M,ans=0;
void dfs(int leftv ,int m , int A , int lastR , int lastH)
{
///剪枝
if(A>ans&&ans)return ;
if(leftv<0)return ;
if( m * (lastR - 1) * (lastR - 1) * (lastH - 1) < leftv && m != M)return;///当前的极限体积小于剩下的体积
///
if(!m)
{
if(!leftv&&(A<ans||!ans))
{
ans=A;
}
return;
}
for(int r = lastR - 1 ; r >= m ; r--)///还剩m层,因此最小半径为m
{
for(int h = lastH - 1 ; h >= m ; h--)
{
///剪枝
if(A+2*leftv/r > ans && ans)///从100ms+优化到32ms
return ;
int curv=leftv-r*r*h;
int curA=A+2*r*h;
if(m==M)curA+=r*r;///如果是第一层,就加上底面积
dfs(curv , m - 1 , curA , r , h);
}
}
}
int main()
{
scanf("%d%d",&N,&M);
dfs(N,M,0,100,1000);
cout << ans << endl;
return 0;
}