您的位置:首页 > 其它

poj 1190 生日蛋糕

2016-07-19 21:20 288 查看

poj 1190 生日蛋糕

Time Limit: 1000MS Memory Limit: 10000K

Total Submissions: 17460 Accepted: 6221

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

剪枝

剪枝1:搭建过程中发现已建好的面积已经超过目前求得的最优表面积,或者预见到搭完后面积一定会超过目前最优表面积,则停止搭建 (最优性剪枝)

剪枝2:搭建过程中预见到再往上搭,高度已经无法安排,或者半径已经无法安排,则停止搭建(可行性剪枝)

剪枝3:搭建过程中发现还没搭的那些层的体积,一定会超过还缺的体积,则停止搭建(可行性剪枝)

剪枝4:搭建过程中发现还没搭的那些层的体积,最大也到不了还缺的体积,则停止搭建(可行性剪枝)

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAX_NUM = 20 + 5;
const int MAX_R = 100;
const int MAX_H = 100;
// M层,体积为N
int N, M;
// 最优化表面积
int minArea;
// 当前的表面积
int area;
// n层的最小体积
int minVolumn[MAX_NUM];
// n层的最小表面积
int minA[MAX_NUM];

void init() {
minVolumn[0] = 0;
minA[0] = 0;
for(int i = 1; i <= M; i++) {
// 第i层半径至少i,高度至少i
minVolumn[i] = minVolumn[i - 1] + i * i * i;
minA[i] = minA[i - 1] +  2 * i * i;
}
}

int maxVolumns[MAX_NUM][MAX_R][MAX_H];
// m层,底层最大半径为r,最高高度为h,能凑出的最大体积
int maxVolumn(int m, int r, int h) {
if(maxVolumns[m][r][h] >= 0) {
return maxVolumns[m][r][h];
}
int volumn = 0;
for(int i = 0; i < m; i++) {
volumn += (r - i) * (r - i) * (h - i);
}
maxVolumns[m][r][h] = volumn;
return maxVolumns[m][r][h];
}

// 使用r半径,h高,m层的蛋糕去凑出体积v
// 同时得到最小表面积
int dfs(int v, int m, int r, int h) {
// 递归出口
if(m == 0) {
// 剪枝,层数到了,但体积不为0
if(v){
return 1;
} else {
minArea = min(area, minArea);
return 0;
}
}
// 剪枝,体积已用完
if(v < 0) {
return 2;
}
// 剪枝,剩余m层所需要的体积要大于所拥有的总体积
if(minVolumn[m] > v) {
return 3;
}
// 剪枝,剩余m层的面积加上当前面积还大于等于当前遍历的所有状态的最小面积
if(minA[m] + area >= minArea) {
return 4;
}
// 剪枝,高度或者半径小于剩余层数
if(h < m || r < m) {
return 5;
}
// 剪枝,剩余最大的体积还是小于所需要的体积
if(maxVolumn(m, r, h) < v) {
return 6;
}
// 遍历递归
for(int i = r; i >= m; i--) {
// 底面积
if(m == M) {
area = i * i;
}
for(int j = h; j >= m; j--) {
// 侧面积
area += 2 * i * j;
int flag = dfs(v - i * i * j, m - 1, i - 1, j - 1);
// 回溯
area -= 2 * i * j;
// 剩余最大体积还是小于所需体积的话
// 那么高度更小,还是回小于所需体积的
if(flag == 6) {
break;
}
}
}
}

int main() {
cin >> N >> M;
// 初始化n层的最小面积和最小体积
init();
// 体积大于n层的最小体积,则无法成立
if(minVolumn[M] > N) {
cout << 0 << endl;
} else {
// 底层最大高度
int maxH = (N - minVolumn[M - 1]) / (M * M) + 1;
// 底层最大半径
int maxR = sqrt(double(N - minVolumn[M - 1]) / M) + 1;
// 初始化
area = 0;
minArea = 1 << 30;
memset(maxVolumns, -1, sizeof(maxVolumns));
dfs(N, M, maxR, maxH);
if(minArea == 1 << 30) {
cout << 0 << endl;
} else {
cout << minArea << endl;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息