1. 程式人生 > 實用技巧 >POJ - 1190 生日蛋糕(深搜+神奇的剪枝)

POJ - 1190 生日蛋糕(深搜+神奇的剪枝)

連結:https://ac.nowcoder.com/acm/contest/1015/B

題目描述

7月17日是Mr.W的生日,ACM-THU為此要製作一個體積為Nπ的M層生日蛋糕,每層都是一個圓柱體。

設從下往上數第i(1 ≤ i ≤ M)層蛋糕是半徑為Ri, 高度為Hi的圓柱。當i<M時,要求Ri>Ri+1且Hi>Hi+1。

由於要在蛋糕上抹奶油,為儘可能節約經費,我們希望蛋糕外表面(最下一層的下底面除外)的面積Q最小。

令Q= Sπ

請程式設計對給出的N和M,找出蛋糕的製作方案(適當的Ri和Hi的值),使S最小。

(除Q外,以上所有資料皆為正整數)

輸入描述:

有兩行,第一行為N(N≤10000),表示待制作的蛋糕的體積為Nπ;第二行為M(M≤20),表示蛋糕的層數為M。

輸出描述:

僅一行,是一個正整數S(若無解則S=0)。

示例1

輸入

100
2

輸出

68

備註:

附:圓柱公式體積V=πR2H側面積A’=2πRH底面積A=πR2

有點慚愧的是,我並沒有自己把它寫出來,實在是頭疼,以後有需要的時候還會自己寫一下。

這裡貼下dalao的程式碼作為學習

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int N, M;
const int inf = 0x3f3f3f3f;
int minv[25], mins[25];
int ans;
void dfs(int r, int h, int layer, int v, int s) {
	if(layer == 0) {
		if(v == N && ans > s) ans = s;
		return;
	}
	if(N - v < minv[layer]) return;//剪枝1:總體積減去蛋糕當前層以下的層的總體積
					//小於上面的層所能構成的最小體積 
	if(ans - s < mins[layer]) return;//剪枝2:當前得到的最優解減去蛋糕當前層以下的層的總面積
					//小於上面的層所能構成的最小面積 
	if(s + 2 * (N - v) / r > ans) return;//剪枝3:2 * (N - v) / r 表示剩下的體積能組成最小面積
						//的極限情況,可以證明,同樣的體積組成一個大圓柱體和組成
						//多個比一個大圓柱體小的小圓柱體相比,前者的表面積比後者
						//要小,所以這種表面積最小的情況再加上本層以下的確定的表
						//面積s如果是大於已知最優解s,那麼最終結果一定不會比ans小
						//返回 。(難理解) 
	int i, j;
	for(i = r; i >= layer; i--) {
		if(layer == M) s = i * i; //第一次要加上底面的面積 
		int maxh = min(h, (N - v - minv[layer - 1]) / i / i); //後者為本層高度最高的情況,
									//但再高也不能高過最高高度h 
		for(j = maxh; j >= layer; j--) {
			dfs(i - 1, j - 1, layer - 1, v + i * i * j, s + 2 * i * j);
		}
	}
}
int main() {
	int i;
	minv[0] = mins[0] = 0;
	for(i = 1; i <= 20; i++) {
		minv[i] = minv[i - 1] + i * i * i;
		mins[i] = mins[i - 1] + 2 * i * i;
	}
	while(~scanf("%d %d", &N, &M)) {
		ans = inf;
		dfs((int)sqrt(N), N, M, 0, 0);   //第一和第二個引數分別指最大的半徑和最大的高度  
		if(ans == inf) printf("0\n");
		else printf("%d\n", ans);
	}
    return 0;
}

關於剪枝的一個小總結:

剪枝分為可行性剪枝最優化剪枝

可行性剪枝一般的思考過程就是,我一共需要多少,在最多的情況下也無法達到,或最少的情況下也會超過。

那麼至於最大與最小到底怎麼取到,就本題而言,還有類似的每層遞增的題目,可以考慮我從(1,1)開始每層加一,到現在的層數,面積和即為最小面積。而最大,就是把一個變數限制成最小,就可以取得另一個的最大,而對每一個“另一個”,都有一個“這個”的最大與之對應。

最優化剪枝,就是考慮,我現有的面積和已經比最小面積大了,那麼不用繼續討論。或者,我現有的面積,加上最小面積,也比最小面積大,那麼也可以不再繼續。