luogu P1731 [NOI1999]生日蛋糕

在这里插入图片描述

analysis

搜索

基本框架

显然搜索每一层的h和r即可

关于hi和ri的范围,有如下推导:

根据圆柱体积公式:

V n o w = π r 2 h V_{now}=\pi r^2h Vnow=πr2h

极端情况下,高为1
于是 V n o w = π r 2 V_{now}=\pi r^2 Vnow=πr2
按照题意约掉 π \pi π得到 r = V n o w = N − v n o w r=\sqrt{V_{now}}=\sqrt{N-v_{now}} r=Vnow =Nvnow

而题中还有一个条件,就是 R i &lt; R i + 1 → R i &lt; = R i + 1 − 1 R_i&lt;R_{i+1}\rightarrow R_i&lt;=R_{i+1}-1 Ri<Ri+1Ri<=Ri+11

于是 R ∈ [ l a y e r , m i n ( N − v n o w , r l a y e r + 1 − 1 ) ] R\in[layer,min(\sqrt{N-v_{now}},r_{layer+1}-1)] R[layer,min(Nvnow ,rlayer+11)]

当枚举好R了以后,

V n o w = π R 2 H V_{now}=\pi R^2H Vnow=πR2H

H = V n o w R 2 = ⌊ ( N − v ) / R 2 ⌋ H=\frac{V_{now}}{R^2}=⌊(N-v)/R^2⌋ H=R2Vnow=(Nv)/R2

题中同样还有一个条件,就是 H i &lt; H i + 1 → H i &lt; = H i + 1 − 1 H_i&lt;H_{i+1}\rightarrow H_i&lt;=H_{i+1}-1 Hi<Hi+1Hi<=Hi+11

于是 H ∈ [ l a y e r , m i n ( ⌊ ( N − v ) / R 2 ⌋ , H l a y e r + 1 − 1 ) ] H\in[layer,min(⌊(N-v)/R^2⌋,H_{layer+1}-1)] H[layer,min((Nv)/R2,Hlayer+11)]

剪枝

  • 优化搜索顺序
  1. 定义对于每一层的ri和hi倒序枚举
  • 排除等效冗余
  1. EOF…
  • 可行性剪枝
  1. 鉴于前面用了倒序枚举,一开始枚举的状态可能会过大,因此我们要预算一下最小的体积,如果当前枚举的体积加上最小的后续体积比要求的体积大,那么就不可能在拓展了
  • 最优化剪枝
  1. 借鉴可行性剪枝第一条的思路,预算一下最小的表面积,如果当前表面积加上后续最小表面积大于当前搜出来的最优解的时候就没有必要拓展了
  2. 放缩法估计花费剪枝:

考虑寻找第dep层的h或r和1到dep层的表面积的等或不等关系,从而用第dep层的数据来预判是否最优

第1到dep-1层的表面积可表示为(约掉 π \pi π后,不计上表面积):

S = 2 ∗ ( h [ 1 ] ∗ r [ 1 ] + h [ 2 ] ∗ r [ 2 ] . . . . . . + h [ d e p − 1 ] ∗ r [ d e p − 1 ] ) = 2 ∗ ∑ i − 1 d e p − 1 h [ i ] ∗ r [ i ] S=2*(h[1]*r[1]+h[2]*r[2]......+h[dep-1]*r[dep-1])=2*\sum_{i-1}^{dep-1}h[i]*r[i] S=2(h[1]r[1]+h[2]r[2]......+h[dep1]r[dep1])=2i1dep1h[i]r[i]

对S进行变形:

S = 2 ∗ ( h [ 1 ] ∗ r [ 1 ] + h [ 2 ] ∗ r [ 2 ] . . . . . . + h [ d e p − 1 ] ∗ r [ d e p − 1 ] ) S=2*(h[1]*r[1]+h[2]*r[2]......+h[dep-1]*r[dep-1]) S=2(h[1]r[1]+h[2]r[2]......+h[dep1]r[dep1])

= 2 r [ d e p ] ( h [ 1 ] ∗ r [ 1 ] ∗ r [ d e p ] + h [ 2 ] ∗ r [ 2 ] ∗ r [ d e p ] . . . . . . + h [ d e p − 1 ] ∗ r [ d e p − 1 ] ∗ r [ d e p ] ) =\frac{2}{r[dep]}(h[1]*r[1]*r[dep]+h[2]*r[2]*r[dep]......+h[dep-1]*r[dep-1]*r[dep]) =r[dep]2(h[1]r[1]r[dep]+h[2]r[2]r[dep]......+h[dep1]r[dep1]r[dep])

由于 r [ d e p ] &gt; = r [ i ] , i ∈ [ 1 , d e p ] r[dep]&gt;=r[i],i\in[1,dep] r[dep]>=r[i],i[1,dep]

于是 S &gt; = 2 r [ d e p ] ( h [ 1 ] ∗ r [ 1 ] 2 + h [ 2 ] ∗ r [ 2 ] 2 . . . . . . + h [ d e p − 1 ] ∗ r [ d e p − 1 ] 2 ) S&gt;=\frac{2}{r[dep]}(h[1]*r[1]^2+h[2]*r[2]^2......+h[dep-1]*r[dep-1]^2) S>=r[dep]2(h[1]r[1]2+h[2]r[2]2......+h[dep1]r[dep1]2)

由于第1到dep-1层的体积可表示为(约掉 π \pi π后):

n − v = h [ 1 ] ∗ r [ 1 ] 2 + h [ 2 ] ∗ r [ 2 ] 2 + . . . . . . + h [ d e p − 1 ] ∗ r [ d e p − 1 ] 2 = ∑ i = 1 d e p − 1 h [ i ] ∗ r [ i ] 2 n-v=h[1]*r[1]^2+h[2]*r[2]^2+......+h[dep-1]*r[dep-1]^2=\sum_{i=1}^{dep-1}h[i]*r[i]^2 nv=h[1]r[1]2+h[2]r[2]2+......+h[dep1]r[dep1]2=i=1dep1h[i]r[i]2

于是 S &gt; = 2 ( n − v ) r [ d e p ] S&gt;=\frac{2(n-v)}{r[dep]} S>=r[dep]2(nv)

这个式子意思就是:从1到dep-1层的表面积一定会大于等于 2 ( n − v ) r [ d e p ] \frac{2(n-v)}{r[dep]} r[dep]2(nv)

于是当我们搜到第dep层的时候,可以用这个式子来估计未来的最小预算会不会超过当前的最优值,也就是说当 2 ( n − v ) r [ d e p ] + s n o w &gt; b e s t c o s t \frac{2(n-v)}{r[dep]}+s_{now}&gt;bestcost r[dep]2(nv)+snow>bestcost的时候剪枝

  • 记忆化
  1. 本题没有记忆化的必要

code

#include <bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define ll long long
template<typename T>void read(T &x){
	x=0;char r=getchar();T neg=1;
	while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
	while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
	x*=neg;
}
#define pi 1
#define Val(h,r) (pi*r*r*h)
#define Sur(h,r) (2*pi*r*h)
#define Area(r) (pi*r*r)
#define re register
int n,m;
const int maxn=20000+10;
const int maxm=20;
int minn=INT_MAX;

int minnv[maxm];
int minns[maxm];
int ri[maxm];
int hi[maxm];
void dfs(re int layer,re int nv,re int cost){
	if(cost+Area(ri[m])>minn||2*(n-nv/pi)/ri[layer+1]+cost>minn)
		return;
	if(nv+minnv[layer-1]>n*pi||cost+minns[layer-1]>minn)
		return;
	if(layer<=0){
		if(nv==pi*n)
			minn=min(minn,cost+Area(ri[m]));
		return;
	}
	for(register int r=min(ri[layer+1]-1,(int)sqrt(n-nv/pi));r>=layer;--r){
		for(register int h=min(hi[layer+1]-1,(n-nv/pi)/(r*r));h>=layer;--h){
			ri[layer]=r;
			hi[layer]=h;
			dfs(layer-1,nv+Val(h,r),cost+Sur(h,r));
		}
	}
}


int main(){
	#ifndef ONLINE_JUDGE
	freopen("datain.txt","r",stdin);
	#endif
	
	read(n);
	read(m);
	loop(i,1,m)
		minnv[i]=minnv[i-1]+Val(i,i),
		minns[i]=minns[i-1]+Sur(i,i)+Area(i);
	hi[m+1]=n;
	ri[m+1]=n;
	dfs(m,0,0);
	printf("%d\n",minn/pi);
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值