这道题减枝的要求很高。
首先很重要的一点是遍历的顺序。
建议蛋糕r和h从大到小遍历。因为这道题如果超时,肯定遍历的数据量太大。
直观的,数据量小的时候,当r和h从小到大遍历的更快。当数据量很大,r和h从大到小遍历就更快了。数据量小的时候不可能TLE的,所以r和h从大到小遍历。
既然r和h从大到小遍历,最底层的最大r和h是很好确定的。自然,从蛋糕的底层到顶层遍历最为方便。
蛋糕的总表面积计算 = 所有圆柱体的侧面积 + 最底层蛋糕的底面面积
减枝思路:
1.当前体积 > 蛋糕总体积,return
2.当前表面积 > 最小总表面积,return
3.当剩余的体积 > 最大可以消耗的体积,return
4.当前表面积 + 最小剩余表面积(即剩下所有圆柱的侧面积之和) > 最小总表面积,return
由于圆柱的r越大,侧面积越小。所以最小剩余表面积可以想象为:剩余体积全部形成一个当前允许的最大半径的一个圆柱。这个圆柱的侧面积为当前最小剩余表面积。
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int n, m, mins = INT_MAX;
int sumv = 0, sums = 0;
int flag = 0;
int dfs(int curl, int curr, int curh)
{
if (sumv > n)//1
return 0;
if (sums > mins)//2
return 0;
if (n - sumv > (m - curl) * (curr - 1) * (curr - 1) * (curh - 1))//3
return 0;
if (sums + 2 * (n - sumv) / curr > mins)//4 16ms,去掉减枝4,125ms
return 0;
if (curl == m)
{
if (sumv == n)
{
mins = sums;
flag = 1;
return 0;
}
else
return 0;
}
for (int r = curr - 1; r >= m - curl; r--)//r
{
flag = 0;
for (int h = curh - 1; h >= m - curl; h--)//h
{
if (curl == 0)
sums += r * r;
sums += 2 * r * h;
sumv += r * r * h;
dfs(curl + 1, r, h);
sumv -= r * r * h;
if (curl == 0)
sums -= r * r;
sums -= 2 * r * h;
}
}
return 0;
}
int main()
{
cin >> n >> m;
int resv = n;
for (int i = 1; i < m; i++)
resv -= i * i * i;
double maxr = sqrt(double(resv / m));
double maxh = resv / m * m;
dfs(0, maxr, maxh);
cout << mins << endl;
}