1. 程式人生 > 其它 >1190:生日蛋糕,深搜邏輯思路、列舉、剪枝

1190:生日蛋糕,深搜邏輯思路、列舉、剪枝

原題:http://bailian.openjudge.cn/practice/1190/

描述

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

解法

思路:這個題比較難想(至少對我這種菜鳥),整體思路是深搜+列舉,列舉每一層可能的高度和半徑,搜尋的範圍是底層蛋糕的最大可能半徑和最大可能高度。從底層往上搭蛋糕,半徑和高度都是從大到小試。關鍵在於剪枝。

  • 最優性剪枝:超過目前最優表面積
  • 可行性剪枝:再往上搭的時候,高度或者半徑已經無法安排
  • 可行性剪枝:搭建過程中發現還沒搭的那些層的體積(最小的)一定會超過還缺的體積,說明前面搭多了
  • 可行性剪枝:搭建過程中發現還沒搭的那些層的體積,最大也到不了還缺的體積,說明前面搭少了
 1 #include <iostream>
 2
#include <vector> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #define INF 1<<30 7 using namespace std; 8 int N, M; 9 int minArea;//最優表面積 10 int area;//正在搭建中的蛋糕表面積 11 int minV[30];//minV[n]表示n層蛋糕最少的體積 12 int minA[30];//minA[n]表示n層蛋糕最少側表面積 13 int MaxVforNRH(int
n, int r, int h) { 14 //求在n層蛋糕,底層最大半徑為r、最高高度為h的情況下,能湊出來的最大體積 15 int v = 0; 16 for (int i = 0; i < n; i++) 17 v += (r - i)*(r - i)*(h - i); 18 return v; 19 } 20 void dfs(int v, int n, int r, int h) 21 {//用n層去湊體積v,最底層半徑不超過r,高度不超過h,求出最小表面積放入minArea 22 if (n == 0) { 23 if (v) 24 return; 25 else { 26 minArea = min(area, minArea); 27 return; 28 } 29 } 30 if (v <= 0) 31 return; 32 if (minV[n] > v)//還沒搭的那些層的體積一定會超過還缺的體積,說明前面搭多了 33 return; 34 if (area + minA[n] >= minArea)//最優性剪枝 35 return; 36 if (h < n || r < n)//高度或者半徑已經無法安排 37 return; 38 if (MaxVforNRH(n, r, h) < v)//搭建過程中發現還沒搭的那些層的體積,最大也到不了還缺的體積,說明前面搭少了 39 return; 40 for (int rr = r; rr >= n; rr--) { 41 if (n == M)//底面積 42 area = rr * rr; 43 for (int hh = h; hh >= n; hh--) { 44 area += 2 * rr*hh; 45 dfs(v - rr * rr*hh, n - 1, rr - 1, hh - 1); 46 area -= 2 * rr*hh;//回溯 47 } 48 } 49 } 50 int main() 51 { 52 cin >> N >> M; 53 minV[0] = 0; 54 minA[0] = 0; 55 for (int i = 1; i <= M; i++) { 56 minV[i] = minV[i - 1] + i * i*i; 57 minA[i] = minA[i - 1] + 2 * i*i; 58 } 59 if (minV[M] > N) 60 cout << 0 << endl; 61 else { 62 //最底層體積不超過N-minV[M-1] 63 int maxH = (N - minV[M - 1]) / (M*M) + 1;//底層最大高度 64 int maxR = sqrt(double(N - minV[M - 1]) / M) + 1;//底層高度至少M 65 area = 0; 66 minArea = INF; 67 dfs(N, M, maxR, maxH); 68 if (minArea == INF) 69 cout << 0 << endl; 70 else 71 cout << minArea << endl; 72 } 73 return 0; 74 }