中文题目而且这么短小的题干相信大家都看的很明白(笑着哭),我就不说了。题目对每一层的半径和高度都有限制,下层的半径和厚度要大于上层的半径和厚度 Ri > Ri-1, Hi > Hi-1,且半径和厚度均为整数。这样的话肯定是用搜索没错了,但是还有一些情况根本不会得到解,我们就没必要再浪费时间走下去了,这样就需要剪枝。具体情况具体分析,代码如下
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
int v,M,mins;
int leftmins[21],leftminv[21];
///leftmins[i]表示第i层及其之上各层的最小表面积,另一个表示最小体积
void dfs(int v,int m,int lastr,int lasth,int sums)
{
/*v:剩余体积
m:剩余层数
lastr:下一层半径
lasth:下一层高度
sums:已经搭好的表面积的和*/
if(m == 0 && v == 0)
{
if(sums < mins)
mins = sums;
return;
}
if(leftmins[m] + sums >= mins)
return;
if(leftminv[m] > v)
return;
///剪枝
int avgv = v / m;
for(int r = lastr - 1;r >= m; r--)
{
for(int h = lasth - 1;h >= m; h--)
{
int curv = r * r * h;
if(curv < avgv)
break;
if(curv > v)
continue;
int leftmaxv = 0;
for(int i = 1;i < m; i++)
leftmaxv += (r - i) * (r - i) * (h - i);
if(v - curv > leftmaxv)
break;
if(m == M)
sums = r * r;
dfs(v - curv,m - 1,r,h,sums + 2 * r * h);
}
}
}
int main()
{
for(int i = 1;i <= 20; i++)
for(int j = 0;j < i; j++)
{
leftmins[i] = (i - j) * (i - j);
leftminv[i] = (i - j) * (i - j) * (i - j);
}
scanf("%d %d",&v,&M);
mins = inf;
dfs(v,M,sqrt(1.0 * v) + 1,v + 1,0);
int ans = mins < inf ? mins : 0;
printf("%d\n",ans);
return 0;
}