题意:
给出平面上n个点和一个角度α,一个比值p;
求一个长轴与x轴夹角为α,长轴与短轴比值为p的椭圆,
包含了这n个点,且使半短轴最小;
题解:
本来只是上bz找找计算几何凸包啥的裸题刷刷,结果怎么碰上这么一个玄学的玩意。。。
况且这题还不用凸包;
看起来只是将圆拓展到了椭圆,但是直接按原模型乱搞似乎有些难度;
判断点和椭圆的关系需要一部转化;
两点间求椭圆,甚至三点间求椭圆都并不好搞,而且还有一个旋转的角度要考虑;
所以不能硬上,要转化模型,转化到熟悉的模型就可以搞了嘛;
将圆变成椭圆需要两步:旋转,放缩;
那么把坐标系下所有点反向旋转放缩一遍,这题就是在求最小圆覆盖了;
转化后的半短轴和圆的半径相同;
随机增量法这个。。。反正我是信了!
代码:
#include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> #define N 51000 using namespace std; const double EPS=1e-8; const double INF=1e100; struct Point { double x,y; friend bool operator <(Point a,Point b) { if(fabs(a.x-b.x)<=EPS) return a.y<b.y; return a.x<b.x; } friend Point operator +(Point a,Point b) { return (Point){a.x+b.x,a.y+b.y}; } friend Point operator -(Point a,Point b) { return (Point){a.x-b.x,a.y-b.y}; } friend Point operator *(double a,Point b) { return (Point){a*b.x,a*b.y}; } friend double operator *(Point a,Point b) { return a.x*b.y-b.x*a.y; } friend double dis(Point a,Point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } friend Point Rotate(Point a,double alpha) { return (Point){a.x*cos(alpha)-a.y*sin(alpha),a.x*sin(alpha)+a.y*cos(alpha)}; } }a[N]; struct Line { Point p,v; friend Point get_Point(Line a,Line b) { Point u=a.p-b.p; double temp=(b.v*u)/(a.v*b.v); return a.p+temp*a.v; } }l1,l2; struct Circle { Point o; double r; bool Is_in(Point a) { if(dis(o,a)<=r+EPS) return 1; else return 0; } }O; int main() { int n,m,i,j,k; double alpha,p; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); scanf("%lf%lf",&alpha,&p); alpha=-alpha/180*acos(-1); for(i=1;i<=n;i++) { a[i]=Rotate(a[i],alpha); a[i].x/=p; } random_shuffle(a+1,a+n+1); O.o=a[1],O.r=0; for(i=1;i<=n;i++) { if(O.Is_in(a[i])) continue; O.o=(Point){(a[1].x+a[i].x)/2,(a[1].y+a[i].y)/2}; O.r=dis(O.o,a[i]); for(j=1;j<i;j++) { if(O.Is_in(a[j])) continue; O.o=(Point){(a[i].x+a[j].x)/2,(a[i].y+a[j].y)/2}; O.r=dis(O.o,a[i]); for(k=1;k<j;k++) { if(O.Is_in(a[k])) continue; l1.p=(Point){(a[i].x+a[j].x)/2,(a[i].y+a[j].y)/2}; l1.v=Rotate(a[i]-a[j],acos(-1)/2); l2.p=(Point){(a[j].x+a[k].x)/2,(a[j].y+a[k].y)/2}; l2.v=Rotate(a[j]-a[k],acos(-1)/2); O.o=get_Point(l1,l2); O.r=dis(O.o,a[i]); } } } printf("%.3lf",O.r); return 0; }
时间: 2024-10-06 21:19:34