[WC 2015复习](六)计算几何

都是比较简单SB的东西,求各位去WC的神犇勿喷。

1、最小圆覆盖

(1)[BZOJ 3564][SHOI/HBOI 2014]信号增幅仪

http://www.lydsy.com/JudgeOnline/problem.php?id=3564

此题很裸,对每个点的坐标稍作处理即可直接套最小圆覆盖算法。最小圆覆盖的细节不需多说,我只想讲一下怎么求三角形外接圆的圆心

以下斜体高亮内容来自网上,作者不知,在此表示歉意。

已知三角形三个点p0、p1、p2的坐标,求外接圆圆心O的坐标

列出方程
sqr(O.x-p0.x)+sqr(O.y-p0.y) = sqr(r);  (1)
sqr(O.x-p0.x)+sqr(O.y-p0.y) = sqr(r);  (2)
sqr(O.x-p0.x)+sqr(O.y-p0.y) = sqr(r);  (3)
联立(1)(2)得
(p1.x-p0.x)*O.x+(p1.y-p0.y)*O.y = (sqr(p1.x)+sqr(p1.y)-sqr(p0.x)-sqr(p0.y))/2; (4)
联立(1)(3)的
(p2.x-p0.x)*O.x+(p2.y-p0.y)*O.y = (sqr(p2.x)+sqr(p2.y)-sqr(p0.x)-sqr(p0.y))/2; (5)
令O.x = p0.x+x;
  O.y = p0.y+y;
带入(4)(5)后化简得到
(p1.x-p0.x)*x+(p1.y-p0.y)*y = (sqr(p1.x-p0.x)+sqr(p1.y-p0.y))/2;
(p2.x-p0.x)*x+(p2.y-p0.y)*y = (sqr(p2.x-p0.x)+sqr(p2.y-p0.y))/2;
分别解得(x,y)
p0+(x,y) = O;


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <cmath>

#define MAXN 51000
#define PI (3.1415926535897384626)
#define EPS (1e-10)

using namespace std;

struct Point //保存坐标系上的点
{
	double x,y;
	
	Point(double xx=0,double yy=0)
	{
		x=xx;
		y=yy;
	}
	
	Point operator-(Point b)
	{
		return Point(x-b.x,y-b.y);
	}
	
	Point operator+(Point b)
	{
		return Point(x+b.x,y+b.y);
	}
	
	double operator*(Point b) //点积
	{
		return x*b.y-y*b.x;
	}
	
	Point operator*(double t) //数乘
	{
		return Point(x*t,y*t);
	}
	
	Point operator/(double t) //数除
	{
		return Point(x/t,y/t);
	}
	
	Point rotate(double ang) //绕原点顺时针旋转ang度
	{
		return Point(x*cos(ang)+y*sin(ang),-x*sin(ang)+y*cos(ang));
	}
	
	Point verl() //逆时针旋转90度后的坐标
	{
		return Point(-y,x);
	}
}dots[MAXN];

int n;

int dcmp(double x) //三态函数
{
	if(fabs(x)<EPS) return 0;
	if(x>EPS) return 1;
	return -1;
}

double dist(Point a,Point b) //求点a到点b距离
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

Point Circumcenter(Point a,Point b,Point c) //
{
	double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;
	double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;
	double d=a1*b2-a2*b1;
	return Point(a.x+(c1*b2-c2*b1)/d,a.y+(a1*c2-a2*c1)/d);
}

double X,Y,R; //最小覆盖圆的圆心是(X,Y),圆的半径是R

void MinCoverCir() //随机增量算法求最小圆覆盖
{
	random_shuffle(dots+1,dots+n+1);
	Point center=dots[1];
	R=0;
	for(int i=2;i<=n;i++)
		if(dist(center,dots[i])+EPS>R) //点i在当前的最小覆盖圆外面
		{
			center=dots[i];
			R=0;
			for(int j=1;j<i;j++)
				if(dist(center,dots[j])+EPS>R)
				{
					center.x=(dots[i].x+dots[j].x)/2;
					center.y=(dots[i].y+dots[j].y)/2;
					R=dist(center,dots[j]); //半径是圆心到第j个点之间的距离
					for(int k=1;k<j;k++)
						if(dist(center,dots[k])+EPS>R) //k在当前的最小覆盖圆外面
						{
							center=Circumcenter(dots[i],dots[j],dots[k]); //i、j、k三点确定最小覆盖圆
							R=dist(center,dots[k]);
						}
				}
		}
}

int main()
{
	double ang,scale;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lf%lf",&dots[i].x,&dots[i].y);
	scanf("%lf%lf",&ang,&scale);
	ang=ang/180*PI; //转为弧度制
	for(int i=1;i<=n;i++)
	{
		dots[i]=dots[i].rotate(ang);
		dots[i].x/=scale;
	}
	MinCoverCir();
	printf("%.3lf\n",R);
	return 0;
}






你可能感兴趣的:([WC 2015复习](六)计算几何)