POJ 1190 生日蛋糕
POJ 1190 生日蛋糕 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 23271 Accepted: 8320 Description
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外,以上所有資料皆為正整數) Input
有兩行,第一行為N(N <= 10000),表示待制作的蛋糕的體積為Nπ;第二行為M(M <= 20),表示蛋糕的層數為M。 Output
僅一行,是一個正整數S(若無解則S = 0)。 Sample Input
100 2 Sample Output
68 Hint
圓柱公式 體積V = πR2H 側面積A’ = 2πRH 底面積A = πR2
重刷POJ的第一題,經典搜尋之——生日蛋糕。 題意:求製作一個m層,體積為v的蛋糕需要奶油的最小表面積,限制條件為:下面一層的半徑以及高度至少要比上一層的大1. 題解:用**dfs(int r 當前的半徑,int h當前的高度,int q當前的表面積,int deep當前的層數,int v當前的體積)**維護 值得深思的是,用dfs搜尋必須要有一個極限,那麼r的極限是什麼?h的極限是什麼? 我們不妨假設整個蛋糕只有一個圓柱,因為體積最大為10000,所以如果其高度為1,那麼r最大為100;如果其半徑為1,那麼高度最大為10000; 那麼就可以有如下的程式碼:
dfs(100,10000,0,m,0);
int dfs(int r,int h,int q,int deep,int v) { if(deep<0) return 0; if(deep==0&&v==n){//當滿足條件時,更新最優解。 if(q+pre_r*pre_r<ans) ans=q+pre_r*pre_r; return 0; } /* 從最下層往上列舉。 */ for(int i=r-1;i>=deep;i--) { if(deep==m) pre_r=i; for(int j=h-1;j>=deep;j--) { dfs(i,j,q+2*i*j,deep-1,v+i*i*j); } } }
這樣還不行,我們還需要考慮剪枝
- 從下往上列舉;
- 當deep<0時return;
- 當 當前體積大於n,return;
- 當 當前表面積大於ans;return;
- 當 就算剩下的層數取最大體積仍不足以使體積≥v;return
以下為程式碼:
#include <iostream>
using namespace std;
int n,m;
int ans=0x7fffffff;
int pre_r;//最下面一層的半徑
int dfs(int r,int h,int q,int deep,int v)
{
if(q+pre_r*pre_r>ans||v>n||deep<0) return 0;//剪枝2、3、4
if(deep==0&&v==n){
if(q+pre_r*pre_r<ans) ans=q+pre_r*pre_r;
return 0;
}
for(int i=r-1;i>=deep;i--)//剪枝1
{
if(deep==m) pre_r=i;
for(int j=h-1;j>=deep;j--)
{
//****************************//**剪枝5**
int sum=0;
for(int k=0;k<=deep-1;k++)
sum+=(i-k)*(i-k)*(j-k);
if(sum+v<n)continue;
//********************************
dfs(i,j,q+2*i*j,deep-1,v+i*i*j);
}
}
}
int main()
{
cin>>n>>m;
dfs(100,10000,0,m,0);
if(ans==0x7fffffff) ans=0;
cout<<ans<<endl;
}