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

来源:互联网 发布:淘宝买保险好吗 编辑:程序博客网 时间:2024/05/28 06:07

都是比较简单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),圆的半径是Rvoid 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;}






0 0
原创粉丝点击