本题整了大半个下午,由于本渣渣刚开始做搜索+剪枝,搜索就够整好久了,剪枝是更加想不到,只能百度向大神学习,整了两个多小时也算是搞明白了情况。
首先这题题目感觉是表达不清,明明就是顶层不涂奶油,底层要涂,不造我为毛理解反了,S就是底层面积+所有的侧面积,首先打表算出来1-x层的最小体积和最小面积,然后从下往上搜索,要枚举当前层可能的r和h,这个工作量是非常大的,所以必须要用剪枝。
1.当前剩余体积<当前层往上最小体积,return
2.当前最优解-当前面积<=当前层往上的最小面积,return;
3.最神奇的剪枝,直接从TLE到0ms,当前面积+2*剩余体积/当前r>=当前最优解,return;剩余体积是sigma(ri*ri*hi),将其看成和当前层一样粗细的圆柱体,乘2除以当前半径就是这个圆柱体的侧面积,而真实情况必然大于等于这种圆柱体的情况,所以可以直接pass。
下面是代码。给个数据 10000 8 答案是1532.
#include <iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,m,temp=100000000,mv[25],ms[25],count=0;
void dfs(int v,int num,int r,int h,int s)
{
if(num==0)
{
if(s<temp&&v==0) temp=s;
return;
}
if(v<mv[num]||temp-s<=ms[num]||2*v/r+s>=temp)return;//三个剪枝。
for(int r1=r; r1>=num; r1--)
{
if(num==m)s=r1*r1;
int h1=min(h,v/(r1*r1));//此处我整了好久,直接用h发现跑不动,TLE,用v/(r1*r1)就会有很多上层大于下层的情况,而我一开始没 发现,有一个数据一直不过,也是醉了
for(; h1>=num; h1--)
{
if(v-r1*r1*h1>=0) dfs(v-r1*r1*h1,num-1,r1-1,h1-1,s+2*r1*h1);
}
}
}
int main()
{
cin>>n>>m;
mv[0]=0;
ms[0]=0;
for(int i=1; i<=m; i++)
{
mv[i]=mv[i-1]+i*i*i;
ms[i]=ms[i-1]+2*i*i;
}
dfs(n,m,n+1,n+1,0);//底层半径和高度不可能大于n吧。。。
if(temp==100000000)printf("0\n");
else printf("%d\n",temp);
}
1519


&spm=1001.2101.3001.11974&articleId=42102177&d=1&t=3&u=0a847a9776564ba493acb2893e424b77)

被折叠的 条评论
为什么被折叠?



