標籤:style blog http color 資料 os
題意:
製作一個體積為Nπ(N<=10000)的M(M<=20)層生日蛋糕,每層都是一個圓柱體。
設從下往上數第i(1 <= i <= M)層蛋糕是半徑為Ri, 高度為Hi的圓柱。當i < M時,要求Ri > Ri+1且Hi > Hi+1。
由於要在蛋糕上抹奶油,為儘可能節約經費,我們希望蛋糕外表面(最下一層的下底面除外)的面積Q最小。
令Q = Sπ
請編程對給出的N和M,找出蛋糕的製作方案(適當的Ri和Hi的值),使S最小。
(除Q外,以上所有資料皆為正整數)
分析:
表面積只和底面圓面積和各層側面積有關
Q = Sπ
S = R1*R1 + 2*sigma(Ri*Hi(1<=i<=M))
N = sigma(Ri*Ri*Hi(1<=i<=M))
狀態(i, Ri, Hi, Si-1, Di-1) 轉移---> (i+1, Ri+1, Hi+1, Si, Di)
枚舉變數 Ri,Hi,為了減少狀態數,就要減少Ri,Hi的枚舉範圍。
最初一定有:
M-i<= Ri+1< Ri
M-i<= Hi+1< Hi
剪枝一:
預先計算
minS[i] 表示從上到下第一層到第i層最少要用去的S
minN[i] 表示從上到下第一層到第i層最少要用去的N
則有剪枝:
Si-1 +minS[m-i] >= best //最佳化剪枝
Di-1 + minN[m-i] >= N //可行性剪枝
剪枝二:
從k層到m層增加的側面積
Si-1 + 2*(N-Di-1)/Ri >= best //最佳化剪枝
剪枝三:
如果先枚舉Ri, 則Hi的上界 maxH = min(Hi -1, N - Si-1 - minN[M-i-1]) / (Ri*Ri) ) //可行性剪枝
//先枚舉Hi一樣。。
#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <stack>#include <string>#include <set>#include <map>using namespace std;#define min(a,b) (a) <(b) ? (a):(b)#define INF 0x3f3f3f3fint minN[25], minS[25];int N, M, Min;void init(){ int i; minN[0] = minS[0] = 0; for(i=1; i<=21; ++i) { minS[i] = minS[i-1] + 2 * i * i; minN[i] = minN[i-1] + i * i * i; }}void dfs(int k, int r, int h, int sums, int sumv){ if(k==M){ if(sumv == N && sums < Min) { Min = sums; } return ; } if(sums + minS[M-k] > Min ||sumv + minN[M-k] > N||2*(N-sumv)/r + sums >= Min) return ; for(int i=r-1; i>=M-k; --i) { if(k==0) sums = i * i; int maxH = min( h-1, (N-sumv-minN[M-k-1])/(i*i) ); for(int j=maxH; j>=M-k; --j) dfs(k+1, i, j, sums + 2 * i * j, sumv + i * i * j); }}int main(){ init(); while(cin>>N>>M) { Min = INF; dfs(0, N, N, 0, 0); //K, R, H, SUMS, SUMV if(Min<INF) cout<<Min<<endl; else cout<<0<<endl; } return 0;}