题目链接:http://poj.org/problem?id=1190
Description 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
Input 有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。
Output 仅一行,是一个正整数S(若无解则S = 0)。
Hint 圆柱公式 |
分析:
我们可以把所有符合要求的蛋糕都制作出来,然后在这里面挑表面积最小的一个输出它的表面积。
制作M层的蛋糕,先制作倒数第一层(第M层),然后制作前M-1层。。。以此类推,用到dfs(递归+枚举)。
剪枝条件:
1. 前面制作的蛋糕体积太大了,超过了N。
2. 前面制作的蛋糕体积太大,余下的体积比还需制作的各层加起来的最小体积还小
3. 当前允许的最大高度或者最大半径小于还需制作的蛋糕层数。
4. 当前蛋糕表面积还没做完就已经大于已有蛋糕的最小表面积了
5. 还需制作的体积比还需制作的各层蛋糕加起来的最大体积还要大(完不成任务)。
AC代码:
#include <iostream>
#include <cmath>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int N,M;
int MinArea;
int MinSNext[25],MinVNext[25],MaxV[25];
int CanMax(int m,int r,int h)
{
int Max;
for(int i=0;i<m;i++)
Max += (r-i)*(r-i)*(r-i);
return Max;
}
void dfs(int v,int m,int r,int h,int area)
{
if(m == 0) {
if(v == 0)
MinArea = min(MinArea,area);
return;
}
if(v <= 0 || h < m || r < m || v < MinVNext[m] || area+MinSNext[m] >= MinArea || v > CanMax(m,r,h))
return;
for(int rr=r;rr>=m;rr--) {
if(m == M)
area = rr*rr; // 底面面积
for(int hh=h;hh>=m;hh--)
dfs(v-rr*rr*hh,m-1,rr-1,hh-1,area+2*rr*hh);
}
}
int main()
{
cin >> N >> M;
MinArea = INF;
MinVNext[0] = 0;
MinSNext[0] = 0;
for(int i=1;i<=20;i++) {
MinVNext[i] = MinVNext[i-1] + (i*i)*i;
MinSNext[i] = MinSNext[i-1] + 2*i*i;
}
int MaxH = (N-MinVNext[M-1])/M*M;
int MaxR = sqrt((N-MinVNext[M-1])/M);
dfs(N,M,MaxR,MaxH,0);
if(MinArea == INF)
MinArea = 0;
cout << MinArea << endl;
}