POJ 生日蛋糕(DFS 巧妙剪枝)
2016-12-06 14:02
330 查看
[align=center]生日蛋糕[/align]
[align=left]原题链接:http://poj.org/problem?id=1190[/align]
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
[align=left]有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。[/align]
Output
[align=left]仅一行,是一个正整数S(若无解则S = 0)。[/align]
Sample Input
Sample Output
Hint
圆柱公式
体积V = πR2H
侧面积A' = 2πRH
底面积A = πR2
[align=left]
[/align]
[align=left]ps:太水的我做这道题的时候全程一脸懵逼。。[/align]
[align=left]代码:[/align]
[align=left]原题链接:http://poj.org/problem?id=1190[/align]
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
[align=left]有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。[/align]
Output
[align=left]仅一行,是一个正整数S(若无解则S = 0)。[/align]
Sample Input
100 2
Sample Output
68
Hint
圆柱公式
体积V = πR2H
侧面积A' = 2πRH
底面积A = πR2
[align=left]
[/align]
[align=left]ps:太水的我做这道题的时候全程一脸懵逼。。[/align]
[align=left]代码:[/align]
//此题使用DFS+剪枝 此题把面积和体积的圆周率都省去了 #include <iostream> #include <cmath> using namespace std; #define INF 1000000 int mins[21], minv[21]; #define min(a, b) (a<b?a:b) int n, m, best; void init() { int i; for(i = 1; i < 21; i++) { //注意此题所有半径和高度都是正整数,所以可得下面的式子 mins[i] = mins[i - 1] + 2 * i * i; //mins表示从最上面一层到 i 层的最小表面积(这里仅仅算了侧面) minv[i] = minv[i - 1] + i * i * i; //minv表示从最上面一层到 i 层的最小体积 } } //dfs从m层开始向上搜索,一直搜索到0层结束 //deep表示该层层数,sums表示在deep + 1 -> m得到的表面积, sumv表示deep + 1 -> m得到的体积,r表示deep + 1的半径,h表示deep + 1的高度 void dfs(int deep, int sums, int sumv, int r, int h) { if(!deep) { if(sumv == n && sums < best) best = sums; return ; } //这里用到的三个剪枝 //sums + mins[deep]> best 表示以前的到的deep + 1层到 m 层的表面积加上从顶层到deep层的最小表面积如果都大于了已经得到的best,那么1到deep层是无论半径和高度取何值都是无效的 //sumv + minv[deep] > n同理 // 2 * (n - sumv) / r + sums >= best 这是该题的精髓,如果没有的话会造成超时,是为了把sumv和sums联系起来,原因如下: // 假设能够得到best时(为什么这样假设呢,因为如果得不到的话那么就已经被第一个剪枝滤去了,所以在第三个剪枝验证时表示已经通过了第一个剪枝的要求), // n - sumv = h[1] * r[1] * r[1] + ... + h[deep] * r[deep] * r[deep] < h[1] * r[1] * r + ... + h[deep] * r[deep] * r (因为r是deep + 1层的半径) //其中h[1]...h[deep]表示在函数的形参情况下,1到deep层应该取得h值,r[1]同理 // 两边同时处以r 再乘以2得 2 * (n - sumv) / r < 2 * (h[1] * r[1] + ... + h[deep] * r[deep]) // 2 * (n - sumv) / r < best - sums // 2 * (n - sumv) / r + sums < best 成立 ,则可得剪枝条件 if(sums + mins[deep] > best || sumv + minv[deep] > n || (2 * (n - sumv) / r + sums >= best)) return; int i, j, maxh; for(i = r - 1; i >= deep; i--) { if(deep == m) sums = i * i;//第m层的表面积 maxh = min(n - sumv - minv[deep - 1] / i * i, h - 1); for(j = maxh; j >= deep; j--) dfs(deep - 1, sums + 2 * i * j, sumv d192 + j * i * i, i, j); } } int main() { init(); best = INF; //将best置成一个很大的值 cin >> n >> m; dfs(m, 0, 0, sqrt(n) + 1, n + 1); //初始条件m层上一层的半径为sqrt(n) + 1是在h等于1时得到的上限,高度h表示半径为1时得到的上限 if(best == INF) cout << 0 << endl; else cout << best << endl; return 0; }
相关文章推荐
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ 生日蛋糕(DFS 巧妙剪枝)
- POJ-1190-生日蛋糕-DFS(深搜)-枚举-多重剪枝
- POJ 1190 生日蛋糕 (dfs + 神剪枝)
- POJ 1190 生日蛋糕(DFS+剪枝)
- Poj 1190 生日蛋糕 (DFS 剪枝)
- POJ-1190-生日蛋糕-DFS(深搜)-枚举-多重剪枝
- poj 1190 dfs+剪枝(生日蛋糕)
- POJ 1190 生日蛋糕(DFS:优化剪枝)