题目描述:
题目链接: http://poj.org/problem?id=3737
题目大意:给定圆锥的表面积S ,求这个圆锥的最大体积V ,以及此时它的高h 与底面半径r,答案小数点后保留两位。
样例输入:
30
样例输出:
10.93
4.37
1.55
题目分析:
首先知道以下公式:
S=π∗r∗l+π∗r2
h=l2−r2−−−−−√
V=13∗π∗r2∗h
可以看出,V 是关于r 的一个二次函数(单峰函数),因此可以三分底面半径,而确定了底面半径,又知道表面积,则其他值都可以依次计算出来,就能计算体积,三分找到最大值。
好吧,细心的同学会发现,貌似V是关于r的开口向上的二次函数,且顶点过原点,只有最小值为0,没有最大值。但实际上,因为S固定,所以h可以用S,r,π表示出来,最后其实是一个开口向下的单峰函数。推演过程如下:
l=Sπ∗r−r
h=l2−r2−−−−−√=S2π2∗r2−2∗Sπ−−−−−−−−−√
V=13∗π∗r2∗h=13∗π∗r2∗S2π2∗r2−2∗Sπ−−−−−−−−−√=13∗r∗S2−2∗S∗π∗r2−−−−−−−−−−−−−−√
PS:本题多组数据。
附代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<cmath>
#include<iomanip>
#include<algorithm>
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-6;
double s,l,r,mid1,mid2,rr,ll;
double find(double r)
{
double l=(s-r*r)/r;
double h=sqrt(l*l-r*r);
double v=pi*r*r*h/3;
return v;
}
int main()
{
//freopen("lx.in","r",stdin);
//freopen("ans1.out","w",stdout);
while(scanf("%lf",&s)!=EOF)
{
s=s/pi;
l=0;r=sqrt(s);
while(r-l>eps)
{
mid1=l+(r-l)/3;mid2=r-(r-l)/3;
double x1=find(mid1);
double x2=find(mid2);
if(x1<x2)
{
l=mid1;
rr=mid2;
}
else
{
r=mid2;
rr=mid1;
}
}
double ll=(s-rr*rr)/rr;
double h=sqrt(ll*ll-rr*rr);
double v=pi*rr*rr*h/3;
printf("%0.2f\n%0.2f\n%0.2f\n",v,h,r);
}
return 0;
}