生日蛋糕——深搜+剪枝

參考:點擊打開鏈接

作者:1300012964

<pre name="code" class="cpp">/*
生日蛋糕
查看 提交 統計 提問
總時間限制: 5000ms 內存限制: 65536kB
描述
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)。
樣例輸入
100
2
樣例輸出
68
提示
圓柱公式
體積V = πR2H
側面積A' = 2πRH
底面積A = πR2
思路:
設最底層爲M層
逐個嘗試底層蛋糕的大小,R,H,剩餘體積(即爲rest_V)減小,面積增大,
繼續求解剩餘體積下,直至V==0,此時獲得一個s,用一個res比較,嘗試所有的情況,獲得最小的S
初始我們給出體積爲V,層數爲M,所以我們知道第M層的半徑R>=M且H>=M,
所以我們可以通過第M層圓柱的體積R^2*H_max=Vm<V 得出第M層高H的最大值H_max<V/(R*R)+1 ,
同理可以推出R_max<srqt(V/M)+1.
枚舉時下一層的r和h 都必須比上一層的小
單單這樣搜索,很容易TLE,必須剪枝
剪枝一:
如果剩下的體積只作成一個圓柱體的話,得到的側面積是最小的
但是這種情況下所得的側面積還是比res大的話,則剪枝
此時的最小側面積的算法爲 2*rest_V/(pre_R-1)--->這裏r=pre_R-1最大,s最小
剪枝二:
如果剩餘的最上面幾層的最小體積大於剩餘的體積rest_V,則退出
上面floor層的最小體積用Min_V[floor]記載,則每一層的r,h取floor
如果當前的面積加上剩餘最上面幾層的最小面積大於最小面積res,則退出
上面floor層的最小體積用Min_S[floor]記載,則每一層的r,h取floor

*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int N,M;
int res = 9999999;
int Min_V[22],Min_S[22];
void Search(int rest_V,int curr_S,int floor,int pre_R,int pre_H) 
	//pre_R和pre_H爲上一層蛋糕的R和H
{
	if(floor == 0)
	{
		if(rest_V == 0 && curr_S < res)
			res = curr_S;
		return;
	}
	//剪枝一:
	if(pre_R > 1 && 2*rest_V/(pre_R-1) + curr_S > res)
		return;
	//剪枝二:
	if(rest_V < Min_V[floor] || curr_S + Min_S[floor] >= res)
		return;
	for(int r = pre_R - 1;r >= floor; --r)
	{
		if(floor == M)
			curr_S = r*r;
		for(int h = pre_H - 1; h >= floor; --h)
			Search(rest_V-r*r*h,curr_S+2*r*h,floor-1,r,h);
	}
}
int main()
{
   scanf("%d%d",&N,&M);
   Min_S[0] = Min_V[0] = 0;
   for(int i = 1; i <=20; ++i)
   {
	   Min_S[i] = Min_S[i-1] + i*i;
	   Min_V[i] = Min_V[i-1] + i*i*i;
   }
   int MaxR = sqrt(1.0*N/M) + 1;
   int MaxH = (1.0*N)/(M*M) + 1;
   Search(N,0,M,MaxR,MaxH);
   if(res == 9999999)
	   printf("0\n");
   else
	   printf("%d\n",res);
   system("pause");
   return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章