您的位置:首页 > 其它

UVA 1473&LA 4986 - Dome of Circus

2013-10-04 14:44 387 查看
题意:给出空间内一些Z>0的点,保证有点不在Z轴上,求一个体积最小的包含所有点的圆锥,输出其h和r。

思路:基本所有人都能想到二维化,问题就转化成了在第一象限内有一些y>0的点,用一条斜率<0的直线覆盖它们。很容易证明最优解的直线应该过其中一个或两个点,再推算一下可以得出,过点(x,y)的最优解为r = 1.5x,h = 3y,越接近它V越小。这样问题就简单明了了,先做一个凸包,再找出上凸包中斜率<0的边所过的点,枚举这些点的最优解就行了。

做这题时WA了好几发,害得我以为是精度问题,后来才知道,是INF开小了(╯' - ')╯ ┻━┻ (掀桌子)。于是我把所有涉及精度的部分全还原了┬—┬ ノ( ' - 'ノ) (摆好摆好),发现跑出来时间还是242ms,(╯°Д°)╯ ┻━┻(再他妈的掀一次)。

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 10010
struct Point{
double x, y;
Point(double _x = 0, double _y = 0):x(_x), y(_y){}
Point operator-(const Point &P)const{ return Point(x-P.x, y-P.y); }
bool operator< (const Point &p)const{ return (x<p.x||(x==p.x&&y<p.y)); }
};
double Cross(const Point &A, const Point &B){ return A.x*B.y-A.y*B.x; }
Point p
,ch
;
double a
;
double getx(Point A, Point B){
return (A.x*B.y-B.x*A.y)/(B.y-A.y);
}
double gety(Point A, Point B){
return (A.x*B.y-B.x*A.y)/(A.x-B.x);
}
int main(){
int n,m,k,i;
double x,y,z;
while(~scanf("%d",&n)){
for(i = 0; i < n; i++){
scanf("%lf%lf%lf",&x,&y,&z);
p[i].x = sqrt(x*x+y*y);
p[i].y = z;
}
sort(p,p+n);
m = 0;
for(i = 0; i < n; i++){
while(m>1 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]) <= 0) m--;
ch[m++] = p[i];
}
k = m;
for(i = n-2; i >= 0; i--){
while(m>k && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]) <= 0) m--;
ch[m++] = p[i];
}
if(n > 1) m--;
ch[m] = ch[0];
double Min,r,h,R,H;
Min = 8000000000000000000.0; a[k-1] = ch[k-1].x;
for(i = k; i <= m; i++){
if(ch[i].y <= ch[i-1].y) break;
a[i] = getx(ch[i],ch[i-1]);
if(1.5*ch[i-1].x < a[i-1])
r = a[i-1], h = gety(ch[i-1],Point(r,0));
else if(1.5*ch[i-1].x <= a[i])
r = 1.5*ch[i-1].x, h = 3*ch[i-1].y;
else r = a[i], h = gety(ch[i-1],Point(r,0));
if(r*r*h < Min){
Min = r*r*h;
R = r; H = h;
}
}
if(1.5*ch[i-1].x < a[i-1])
r = a[i-1], h = gety(ch[i-1],Point(r,0));
else r = 1.5*ch[i-1].x, h = 3*ch[i-1].y;
if(r*r*h < Min){
R = r; H = h;
}
printf("%.3lf %.3lf\n",H,R);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: