hdu3756Dome of Circus && hdu2438 Turn the corner
hdu3756
题意:在一个三维空间里,已知有N个点,求一个最小的圆锥使所有的点都包含其中。
分析:主要有俩个步骤,首先就是将三维空间转化为二维空间,将所有的点都转化都同一个平面内考虑,通过将(X,Y,Z) 转化为(sqrt(x*x+y*y),Z),
问题就转化为求一条直线将第一象限内的点全部包围起来。
即,求满足条件的h,r 使得 h*r*r最小
对于单调函数的表达式,我们可以采用二分搜索,但对于这种凸函数或凹函数求极值,我们可以采用三分搜索,给定h的上下限,三分h搜索即可。
这里有三分搜索的介绍,挺不错的
http://www.crazyhotice.com/2011/07/%E4%B8%89%E5%88%86%E6%90%9C%E8%8B%8F%E7%AE%97%E6%B3%95/
核心代码:
while(right-left > 1e-6) { lmid = (2.0*left+end)/3.0; rmid = (left+2.0*end)/3.0; if(f(lmid) < f(rmid)) right = rmid; else left = lmid; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define MaxHeight 3000
struct point
{
double x,y;
}p[10005];
int n;
double get_r(double h)
{
double r=0.0;
for(int i=0;i<n;i++)
r=max(r,h*p[i].x/(h-p[i].y));
return r;
}
double ThiDiv(double left,double right)
{
double lm,rm,lr,rr;
while(right-left>1e-5)
{
lm=(left*2+right)/3.0;
rm=(right*2+left)/3.0;
lr=get_r(lm);
rr=get_r(rm);
if(lr*lr*lm<rr*rr*rm)
right=rm;
else left=lm;
}
return left;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
double x,y,low=0.0;
for(int i=0;i<n;i++)
{
scanf("%lf %lf %lf",&x,&y,&p[i].y);
p[i].x=sqrt(x*x+y*y);
if(p[i].y>low)
low=p[i].y;
}
double h=ThiDiv(low,MaxHeight);
printf("%.3f %.3f\n",h,get_r(h));
}
return 0;
}
另一道三分的题目,
hdu2438
题意:已知汽车的长和宽,l和w,以及俩条路的宽为x和y,汽车所处道路宽为x ,问汽车能否顺利转弯?
分析:汽车能否顺利转弯取决于在极限情况下,随着角度的变化,汽车离对面路的距离是否大于等于0
如图中
在上图中需要计算转弯过程中h 的最大值是否小于等于y
很明显,随着角度θ的增大,最大高度h先增长后减小,即为凸性函数,可以用三分法来求解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define pi 3.141592653
double x,y,l,w;
double cal(double a)
{
double s=l*cos(a)+w*sin(a)-x;
double h=s*tan(a)+w*cos(a);
return h;
}
int main()
{
while(scanf("%lf %lf %lf %lf",&x,&y,&l,&w)!=EOF)
{
double left=0.0,right=pi/2;
double lm,rm;
while(fabs(right-left)>1e-6)
{
lm=(left*2.0+right)/3.0;
rm=(left+right*2.0)/3.0;
if(cal(lm)>cal(rm))
right=rm;
else left=lm;
}
if(cal(left)<=y)
printf("yes\n");
else printf("no\n");
}
return 0;
}