其他分享
首页 > 其他分享> > 009

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