009
作者:互联网
题目:https://www.luogu.com.cn/problem/P1731
题目简述:
做一个类似于动漫中的多层蛋糕
在限定体积和层数内寻找可能表面积中的最小值
思路:还是那失了双亲的深搜与剪枝
深搜基本思路:准备一个r[ ]和一个h[ ]分别存储第p层的半径和高
由底层开始,一步一步向上搜索
在体积不超限制的情况下,运用平移可得
整个蛋糕的表面积为每一层的侧面积和最底层的底面积
在比对即可
接下来,就可以开始考虑“剪枝”了
首先是上下界的问题
由于每一层都要比它的下面那层小
因此它的一个界就是它下面一层,也就是上一次我们搜索的那层半径(高)
注意,这一层永远比上一次我们搜索的那层小,记得-1
(我是用的i,j双层循环,一个半径一个高)
而另一个界,就来源于这句话:
要求R[i]>R[i+1]且H[i]>H[i+1]
所以我们需要给这一层上面每一层留一点
所以它的另一个界就是剩余层数(给每一层留个1意思意思得了)
但是在第一次的搜索中需要人为规定上界,否则会炸
其他的剪枝都在代码里,请君自便
#include<bits/stdc++.h>
using namespace std;
int n,m,h[16],r[16],minn=2147483647;
inline void dfs(int v,int k,int p,int s){
//v为剩余体积,k为剩余层数
//p为数组标记,s为当前表面积
if(v<0){//剩余体积不够
//证明本蛋糕体积已经超出限制
return;//再见
}
if(p>m+1){//数组超限
//代表本蛋糕已经不符合层数要求
return;//再见
}
if(s>=minn){//当前表面积超过测出的最小值
//代表本蛋糕并非最优解
return;//再见
}
if(s+k+r[1]*r[1]>minn){
//当前表面积加上上底面积
//再加上每层假定的最小表面积
//(即直接认为以后每层表面积都是1)
//还不是最优解
return;//再见
}
if(v>r[p-1]*r[p-1]*h[p-1]*k){
//当前体积如果大于
//假定的最大体积
//(即直接认为以后每层体积都是上一层的体积)
//还是不够要求
return;//再见
}
//上述就是剪枝1
if(v==0&&p==m+1){
//如果恰好达到要求
s+=r[1]*r[1];//拼上上底面积
if(s<minn){//比曾经的最小值小
minn=s;//替换
}
return;//再见
}
int i,j;
for(i=r[p-1]-1;i>=k;i--){
//开始搜索(具体思路在上文,这里不过多赘述
for(j=h[p-1]-1;j>=k;j--){
if(v>=i*i*j&&p<=m+1){
//当前假定的这层蛋糕没有超过体积上限
//并且层数没有超限
r[p]=i;//r[]存储第p层的半径
h[p]=j;//h[]存储第p层的高
dfs(v-i*i*j,k-1,p+1,s+i*2*j);//搜起来
r[p]=0;//回溯
h[p]=0;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
h[0]=(int)sqrt(n);//极大半径
r[0]=(int)sqrt(n);//极大高
//上面两行就是思路中说的“人为规定上界”
dfs(n,m,1,0);
if(minn==2147483647){//没变,即无解
printf("0");//再见
}
else{//有解
printf("%d",minn);//输出
}
return 0;
}
总结:没什么可说的,该说的都在代码里
标签:一层,剪枝,表面积,return,int,体积,009 来源: https://www.cnblogs.com/a-001/p/16025466.html