POJ-1190-生日蛋糕-DFS(深搜)-枚举-多重剪枝
题目链接:
这个题目非常好,有难度;能够好好的多做做;
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define LL long long
using namespace std;
int MinArea=1<<30; // 存最优表面积。
int MinV[30]; // 存第一层到该层最小体积;
int MinA[30]; // 存第一层到该层最小面积。
int N,M; // 体积,层数。
int area=0; // 存增在搭建的表面积;
int MaxV(int n,int r,int h) // 当有n层时。能够有的最大体积;当中r为最大半径,h为最大高度;
{
int v=0;
for(int i=0;i<n;i++) v+=(r-i)*(r-i)*(h-i);
return v;
}
void dfs(int v,int n,int r,int h)
{
if(n==0){ // 说明一种情况搭建层数已经完毕。
if(v) return;
else{
MinArea=min(MinArea,area); // 能够搭建,则更新最优解。
return;
}
}
if(v<=0) return; // 体积不够,退出。
if(MinV[n]>v) return; // 搭建n层的最小体积比提供的体积大。即无法搭建。退出;
if(area+MinA[n]>=MinArea) return; // 当前搭建表面积加上前n层最小的表面积比最优解更大。则能够退出。
if(h<n||r<n) return; // 最大半径,或者最大高度比层数还要多。则就说明已经无法继续搭建了。
if(MaxV(n,r,h)<v) return; // 这n层能够搭建的最大体积都比提供的体积要小,说明无法按要求搭建;
for(int rr=r;rr>=n;rr--){ // 从最大半径開始枚举搜索。
if(n==M) area=rr*rr; // 底面积;
for(int hh=h;hh>=n;hh--){ // 从最大高度開始枚举。
area+=2*rr*hh; // 搭建的面积更新;
dfs(v-rr*rr*hh,n-1,rr-1,hh-1);
area-=2*rr*hh; // 回溯;
}
}
}
int main()
{
while(~scanf("%d%d",&N,&M)){
MinV[0]=0;
MinA[0]=0;
for(int i=1;i<=M;i++){
MinV[i]=MinV[i-1]+i*i*i; // 前i层最小体积;
MinA[i]=MinA[i-1]+2*i*i; // 前i层最小面积;
}
if(MinV[M]>N) printf("0\n");
else{
int MaxH=(N-MinV[M-1])/(M*M)+1; // 底层最大高度。
int MaxR=sqrt(double(N-MinV[M-1])/M)+1; // 底层最大半径;
int area=0;
MinArea=1<<30;
dfs(N,M,MaxH,MaxR);
if(MinArea==1<<30) printf("0\n");
else printf("%d\n",MinArea);
}
}
return 0;
}

浙公网安备 33010602011771号