[POJ1190] [NOI1999] 生日蛋糕 [搜索][剪枝]

[ L i n k \frak{Link} Link]


题意:
 
 要做一个 V = n π V=n\pi V=nπ n ≤ 1 0 4 , n ∈ Z ∗ n\le10^4,n\in\Z^* n104,nZ)的 m m m m ≤ 20 , m ∈ Z ∗ m\le20,m\in\Z^* m20,mZ)层蛋糕,每一层都是一个圆柱体。
 记从下往上数的第 i i i 1 ≤ i ≤ m 1\le i\le m 1im)层蛋糕是半径为 R i R_i Ri,高度为 H i H_i Hi的圆柱体。
 对 ∀ i &lt; m \forall i&lt;m i<m R i &gt; R i + 1 R_i&gt;R_{i+1} Ri>Ri+1 H i &gt; H i + 1 H_i&gt;H_{i+1} Hi>Hi+1
 我们希望蛋糕外表面(除下底面)的面积 Q = π R 1 2 + ∑ i = 1 n 2 π R i H i Q=\pi{R_1}^2+\displaystyle\sum\limits_{i=1}^n2\pi R_iH_i Q=πR12+i=1n2πRiHi 最小。
 求最小的 S = Q π = R 1 2 + ∑ i = 1 n 2 R i H i S=\dfrac{Q}{\pi}={R_1}^2+\displaystyle\sum\limits_{i=1}^n2R_iH_i S=πQ=R12+i=1n2RiHi
 无解 S = 0 S=0 S=0


也就是说要取 R i , H i R_i,H_i Ri,Hi满足 ∑ i = 1 n R i 2 H i = n \displaystyle\sum\limits_{i=1}^n{R_i}^2H_i=n i=1nRi2Hi=n S = R 1 2 + ∑ i = 1 n 2 R i H i S={R_1}^2+\displaystyle\sum\limits_{i=1}^n2R_iH_i S=R12+i=1n2RiHi最小、求这个最小值。

m ≤ 20 m\le20 m20,又要取 R i , H i R_i,H_i Ri,Hi
感觉上有点像是状态压缩的理论复杂度,不过因为要取两组数,可能会变成 2 40 2^{40} 240
显然不太扛得住?
于是猜测这道题是不可做题,先想暴力。

40 ! 40! 40!炸成天文数字,不过搜索可以剪枝;同时这道题目的模型也比较像是搜索。
那首先我们暴力枚举 R i , H i R_i,H_i Ri,Hi……


上下界
 
i=1
思考一下怎么约束。
因为上表面的面积就是最底下那个圆柱体的上表面面积,可能先确定最下面那个会好一点
那我们从 1 1 1 n n n枚举。如果我们现在先确定 R 1 R_1 R1,因为 ∀ R i , H i ∈ Z ∗ \forall R_i,H_i\in\Z^* Ri,HiZ ∑ i = 1 n R i 2 H i = n \displaystyle{\sum\limits_{i=1}^n{R_i}^2H_i=n} i=1nRi2Hi=n
∀ 1 &lt; i ≤ m \forall 1&lt;i\le m 1<im R i &lt; R i − 1 , H i &lt; H i − 1 R_{i}&lt;R_{i-1},H_i&lt;H_{i-1} Ri<Ri1,Hi<Hi1
简单地限制一下, m ≤ R 1 ≤ n − ∑ i = 2 m V i m\le R_1\le\sqrt{n-\displaystyle\sum\limits_{i=2}^m V_i} mR1ni=2mVi
并且 max ⁡ ( ∑ i = 1 m − 1 i 3 , n − R 1 2 H 1 ) ≤ ∑ i = 2 m V i ≤ ∑ i = 1 m − 1 ( R 1 − i ) 2 ( H 1 − i ) \displaystyle{\max(\sum\limits_{i=1}^{m-1}i^3,n-{R_1}^2H_1)\le\sum\limits_{i=2}^m V_i\le\sum\limits_{i=1}^{m-1}(R_1-i)^2(H_1-i)} max(i=1m1i3,nR12H1)i=2mVii=1m1(R1i)2(H1i)
∴  ∑ i = 2 m V i ≥ [ ( m − 1 ) ( m − 1 + 1 ) 2 ] 2 \displaystyle{\sum\limits_{i=2}^m V_i\ge \left[\frac{(m-1)(m-1+1)}{2}\right]^2} i=2mVi[2(m1)(m1+1)]2
(注:平方和公式 ∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \displaystyle{\sum_{i=1}^ni^2=\frac{n(n+1)(2n+1)}{6}} i=1ni2=6n(n+1)(2n+1);立方和公式 ∑ i = 1 n i 3 = [ n ( n + 1 ) 2 ] 2 \displaystyle{\sum_{i=1}^ni^3=\left[\frac{n(n+1)}{2}\right]^2} i=1ni3=[2n(n+1)]2

我们暂且定 m ≤ R 1 ≤ n − m 4 − 2 m 3 + m 2 4 \displaystyle{m\le R_1\le\sqrt{n-\frac{m^4-2m^3+m^2}{4}}} mR1n4m42m3+m2
同样暂且有 m ≤ H 1 ≤ n − 1 4 ( m 4 − 2 m 3 + m 2 ) R 1 2 \displaystyle{m\le H_1\le \frac{n-\frac{1}{4}(m^4-2m^3+m^2)}{{R_1}^2}} mH1R12n41(m42m3+m2)
然后可以进一步限制成 m ≤ R 1 ≤ n m − 1 4 ( m 3 − 2 m 2 + m ) \displaystyle{m\le R_1\le\sqrt{\frac{n}{m}-{\frac{1}{4}(m^3-2m^2+m)}}} mR1mn41(m32m2+m)
好像有点沙雕,那就先这样吧((


i>1
考虑 R i , H i R_i,H_i Ri,Hi
我们每次可以记录一下上一层取的 R i , H i R_i,H_i Ri,Hi,记作 R r , H r R_r,H_r Rr,Hr来简单限制新一层的 R i , H i R_i,H_i Ri,Hi取值
m − i + 1 ≤ R i ≤ R r − 1 m-i+1\le R_i\le R_r-1 mi+1RiRr1 m − i + 1 ≤ H i ≤ H r − 1 m-i+1\le H_i\le H_r-1 mi+1HiHr1
这样就好,别算太多(


最优性剪枝

然后我们还可以记忆化,记录一下相同状态(第 i i i层取 H i , R i H_i,R_i Hi,Ri的最优解)……?
然而这个 H i , R i H_i,R_i Hi,Ri不能记忆化。

不过我们还可以搞一下这一层往后的最优解?就是理论最小值
加上往后的理论最小侧面积都大于之前搜索到的最优解就剪掉。
同时也可以考虑一下体积?因为体积的限制是"=",所以可以从大&小两个方面限制
在这里我们可以限制,如果加上理论最小体积都大于n就跳掉。
这两个理论最小值都是可以预处理的

现在我们最多就是做不等式放缩最优性剪枝了;
可以记录之前搜索到的最小的 S S S记作 S r S_r Sr,做最优性剪枝;
具体地就是说判断往后能不能取到 S &lt; S r S&lt;S_r S<Sr,不能就cut。

怎么取现在能得到的最小表面积?后面还需要的 V V V显然可以用 n n n减去现在的 V V V得到。

上表面积我们不需要考虑(全部由 π R 1 2 \pi{R_1}^2 πR12承包);
V V V确定的情况下,最小的侧面积和是?
——就是说已知 ∑ j = i + 1 m R j 2 H j \displaystyle{\sum\limits_{j=i+1}^m{R_j}^2H_j} j=i+1mRj2Hj,那么 ∑ 2 R j H j \displaystyle{\sum2R_jH_j} 2RjHj最小是多少?

∑ R j H j ≥ ⋯ ∑ R j 2 H j ⋯ \displaystyle{\sum R_jH_j\ge\cdots\sum{R_j}^2H_j\cdots} RjHjRj2Hj
这个形式有点难看,化差: ∑ [ R j − f ( R j 2 ) ] H j ≥ 0 \displaystyle{\sum\left[R_j-f\left({R_j}^2\right)\right]H_j\ge0} [Rjf(Rj2)]Hj0
现在这个不等式,我们不确定的是这个不等关系到底能不能成立;为什么?
因为后面的 R j , H j R_j,H_j Rj,Hj不确定(需要搜索)。

我们做这个限制显然是没有办法得到之后严格最小侧面积和的(不然直接返回结果了)
只能取估计值。并且这个估计值应该严格不小于实际上最小的侧面积和。(是剪枝不是a*)
我们实际上的问题是,之后能得到的最小侧面积至少是多少
如果连放宽限制的都不优那就更没有希望了。

所以我们现在取这个 f ( R j 2 ) f\left({R_j}^2\right) f(Rj2)应该恒满足对于 j &gt; i j&gt;i j>i f ( R j 2 ) ≤ R j f\left({R_j}^2\right)\le R_j f(Rj2)Rj
显然我们只需要让 R j R_j Rj乘上一个常数 C ≥ R j \mathrm C\ge R_j CRj,又刚好有这么一个 ∀ j &gt; i , R i &gt; R j \forall j&gt;i,R_i&gt;R_j j>i,Ri>Rj
那么剩下那一部分最小侧面积在放宽限制简单考虑的情况下就是 2 ∑ R j 2 H j R i \displaystyle{\frac{2\sum{R_j}^2H_j}{R_i}} Ri2Rj2Hj

判断是否有 S 1 ⋯ i + ∑ R j 2 H j R i ≤ S r \displaystyle{S_{1\cdots i}+\frac{\sum{R_j}^2H_j}{R_i}\le S_r} S1i+RiRj2HjSr即可。
那么关于侧面积,在最小>best上我们有了两个判据。


可行性剪枝

显然还可以在体积上做可行性剪枝(往后能否取到 V ≥ n V\ge n Vn
之前剪了最小>n的,现在来剪最大<n的。
这个我们前面推过了: ∑ i = j + 1 m V i ≤ ∑ i = 1 m − j ( R j − i ) 2 ( H j − i ) \displaystyle{\sum\limits_{i=j+1}^m V_i\le\sum\limits_{i=1}^{m-j}(R_j-i)^2(H_j-i)} i=j+1mVii=1mj(Rji)2(Hji)
判断 V 1 ⋯ i + ∑ i = 1 m − j ( R j − i ) 2 ( H j − i ) ≥ n \displaystyle{V_{1\cdots i}+\sum\limits_{i=1}^{m-j}(R_j-i)^2(H_j-i)\ge n} V1i+i=1mj(Rji)2(Hji)n是否成立即可。
这个算起来有丶难,简单考虑成判断 V 1 ⋯ i + ( m − i ) R i 2 H i ≥ n \displaystyle{V_{1\cdots i}+(m-i){R_i}^2H_i\ge n} V1i+(mi)Ri2Hin,不成立就跳
于是关于体积的就有了最小和最大两个限制。


对拍一下,跑得飞快(maybe
能不能dp啊?然而这个 R , H R,H R,H记录不了啊。也很难转移。


注意细节。
实际上挺简单的。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m, ans = inf;
int minV[25];
int minS[25];
void init() {
	for (register int i = 1; i <= m; ++i) {
		minS[i] = minS[i - 1] + 2 * i * i;
		minV[i] = minV[i - 1] + i * i * i;
	}
}
void dfs(const int &i, const int &rr, const int &hh, const int &v, const int &s) {
	register int t = m - i + 1;
	if (t <= 0) return;
	for (register int r = rr; r >= t; --r) {
		for (register int h = hh; h >= t; --h) {
			register int tv = v + r * r * h, ts = s + 2 * r * h;
			if (ts + 2 * (n - tv) / r >= ans) continue;
			if (ts + minS[m - i] >= ans) continue;
			if (tv + minV[m - i] > n) continue;
			if (tv + (m - i) * (tv - v) < n) continue;
			if (i == m) {
				if (tv == n && ts < ans) ans = ts;
				continue;
			}
			dfs(i + 1, r-1, h-1, tv, ts);
		}
	}
}
int main() {
	scanf("%d%d",&n,&m);
	init();
	for (register int i = sqrt( 1.0 * (1.0 * n - 1.0 * (m*m*m*m - 2*m*m*m + m*m) / 4) / (1.0 * m) ); i >= m; --i ) {
		for (register int j = (int)((1.0*n - 0.25*(m*m*m*m - 2*m*m*m + m*m) / (1.0*i*i))); j >= m; --j) {
			register int tv = i*i*j, ts = i*i+2*i*j;
			if (ts + 2 * (n - tv) / i >= ans) continue;
			if (ts + minS[m - 1] >= ans) continue;
			if (tv + minV[m - 1] > n) continue;
			if (tv + (m - 1) * tv < n) continue;
			if (m == 1) { 
				if (tv == n && ts < ans) ans = ts;
				continue;
			}
			dfs(2, i-1, j-1, i*i*j, i*i+2*i*j);
		}
	}
	if (ans == inf) ans = 0;
	printf("%d", ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值