bzoj-3564 信号增幅仪

141 篇文章 0 订阅
75 篇文章 0 订阅

题意:

给出平面上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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值