2018TYUT暑期ACM模拟赛(6)
Geometry Problem HDU - 6242
题意:给你n个点,然后求圆心和半径,要求这个圆必须过n/2的点。
思路:首先要知道怎么三点确定一个圆。然后用随机数,得三个点,这三个点确定的圆能过多少点。要注意的是,因为求圆心一起半径要用到sqrt函数所以精度这里要注意。还有rand的函数rand()%n的意思是取(0-n-1)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stdlib.h>
using namespace std;
const int maxn=2e5+10;
double X,Y,R;
struct Point{
double x,y;
}pp[maxn];
double dis(Point x,Point y)
{
return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
void solve(Point a,Point b,Point c)//三点共圆圆心公式--码住
{
X=( (a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.y-c.y)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.y-b.y) ) / (2*(a.y-c.y)*(a.x-b.x)-2*(a.y-b.y)*(a.x-c.x));
Y=( (a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.x-c.x)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.x-b.x) ) / (2*(a.y-b.y)*(a.x-c.x)-2*(a.y-c.y)*(a.x-b.x));
R=sqrt((X-a.x)*(X-a.x)+(Y-a.y)*(Y-a.y));
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lf%lf",&pp[i].x,&pp[i].y);//
if(n==1||n==2){//半数
printf("%lf %lf %lf\n",pp[1].x+1,pp[1].y,1.0);
continue;
}
if(n==3||n==4){//要求只要半数就好
X=(pp[2].x+pp[1].x)/2;
Y=(pp[2].y+pp[1].y)/2;
R=dis(pp[1],pp[2])/2;
printf("%lf %lf %lf\n",X,Y,R);
continue;
}
while(1)
{
int a=rand()%n+1;//产生1-n的数字
int b=rand()%n+1;
int c=rand()%n+1;
if(a==b||b==c||a==c) continue;
//排除三点以在同一直线
// cout<<a<<b<<c<<endl;
if(fabs((pp[a].x-pp[b].x)*(pp[c].y-pp[b].y)-(pp[a].y-pp[b].y)*(pp[c].x-pp[b].x))<=1e-6) continue;
solve(pp[a],pp[b],pp[c]);
Point tmp;
tmp.x=X;tmp.y=Y;//圆心
int sum=0;
for(int i=1;i<=n;i++){
//if(a==i||b==i||c==i) continue;
if(fabs(dis(tmp,pp[i])-R)<=1e-6) sum++;//因为求点所以精度会丢失i部分
}
if(2*sum>=n) {
printf("%lf %lf %lf\n",X,Y,R);
break;
}
}
}
return 0;