/*
hdu 6242
题目大意
给你一堆点
求一个能让>=1/2的点在圆上的圆的圆心和半径
首先这个答案肯定不唯一
其次这道题用了随机数(第一次接触这东西)
简单记一下rand()是产生一个数
虽然说是随机但其实并不是
它是系统根据一个数以及对应公式递推产生
这个数如果不设定则是系统在开机时已经确定好了的
而srand()就是来设定这个数(虽然这道题设不设定没多大关系)
再来说一下这题的解决方法
前面写了,这题利用随机数来AC
大体思路就是
把点存入结构体数组
然后利用随机数随机选取三个点
因为三点可以确定一个圆
然后看这个圆满不满足要求
满足就输出结果
另外至于为什么可以利用随机数来做是因为
每个点对于符合要求的圆在圆上的可能性是0.5,不在也是0.5
要随机选取三个点都在圆上的概率 P=0.5*0.5*0.5=0.125
也就是说从理论上只要随机选取8次就能找到满足条件的圆
考虑到比较背,也不会需要太多次,时间应该是足够的
最后特判点数n<5的情况(这个可以直接确定)
另外做这题我知道了
#include <bits/stdc++.h>这个头文件表示
包含所有c++的头文件
*/
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const double eps=1e-6;
struct point
{
double x,y;
} p[200005];
double dis(point a,point b)
{
return sqrt(((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y)));
}
point work(point a,point b,point c)//三点共圆圆心公式
{
point q;
q.x=((c.y-a.y)*(c.y-b.y)*(b.y-a.y)+(a.x*a.x-b.x*b.x)*(c.y-a.y)-(a.x*a.x-c.x*c.x)*(b.y-a.y))/(2*((c.y-a.y)*(a.x-b.x)-(a.x-c.x)*(b.y-a.y)));
q.y=((c.x-a.x)*(c.x-b.x)*(b.x-a.x)+(a.y*a.y-b.y*b.y)*(c.x-a.x)-(a.y*a.y-c.y*c.y)*(b.x-a.x))/(2*((c.x-a.x)*(a.y-b.y)-(a.y-c.y)*(b.x-a.x)));
return q;
}
int main()
{
srand(time(NULL));
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
if(n==1||n==2)
{
printf("%lf %lf %lf\n",p[0].x+1,p[0].y,1.0);
continue;
}
if(n==3||n==4)
{
printf("%lf %lf %lf\n",(p[0].x+p[1].x)/2,(p[0].y+p[1].y)/2,dis(p[0],p[1])/2);
continue;
}
while(1)
{
int a=rand()%n;
int b=rand()%n;
int c=rand()%n;
if(a==b||a==c||b==c)
continue;
point p1,p2;
p1.x=p[a].x-p[b].x;
p1.y=p[a].y-p[b].y;
p2.x=p[c].x-p[b].x;
p2.y=p[c].y-p[b].y;
if(fabs(p1.x*p2.y-p1.y*p2.x)<=eps)//考虑到精度的关系double只能保存到小数点后6位,所以如果比这个还小就近似的认为在一条线上了
continue; //顺便记录一下,这是叉积
point po=work(p[a],p[b],p[c]);//找到圆心
double r=dis(p[a],po);//圆心到任意一点就是半径
int sum=0;
for(int i=0; i<n; i++)//用该圆对每个点比较一下,看是否在圆上
{
if(fabs(dis(p[i],po)-r)<=eps)//依然是因为精度关系,如果比1e-6还小就近似认为在圆上了
sum++;
}
if(2*sum>=n)
{
printf("%lf %lf %lf\n",po.x,po.y,r);
break;
}
}
}
return 0;
}
hdu 6242
题目大意
给你一堆点
求一个能让>=1/2的点在圆上的圆的圆心和半径
首先这个答案肯定不唯一
其次这道题用了随机数(第一次接触这东西)
简单记一下rand()是产生一个数
虽然说是随机但其实并不是
它是系统根据一个数以及对应公式递推产生
这个数如果不设定则是系统在开机时已经确定好了的
而srand()就是来设定这个数(虽然这道题设不设定没多大关系)
再来说一下这题的解决方法
前面写了,这题利用随机数来AC
大体思路就是
把点存入结构体数组
然后利用随机数随机选取三个点
因为三点可以确定一个圆
然后看这个圆满不满足要求
满足就输出结果
另外至于为什么可以利用随机数来做是因为
每个点对于符合要求的圆在圆上的可能性是0.5,不在也是0.5
要随机选取三个点都在圆上的概率 P=0.5*0.5*0.5=0.125
也就是说从理论上只要随机选取8次就能找到满足条件的圆
考虑到比较背,也不会需要太多次,时间应该是足够的
最后特判点数n<5的情况(这个可以直接确定)
另外做这题我知道了
#include <bits/stdc++.h>这个头文件表示
包含所有c++的头文件
*/
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const double eps=1e-6;
struct point
{
double x,y;
} p[200005];
double dis(point a,point b)
{
return sqrt(((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y)));
}
point work(point a,point b,point c)//三点共圆圆心公式
{
point q;
q.x=((c.y-a.y)*(c.y-b.y)*(b.y-a.y)+(a.x*a.x-b.x*b.x)*(c.y-a.y)-(a.x*a.x-c.x*c.x)*(b.y-a.y))/(2*((c.y-a.y)*(a.x-b.x)-(a.x-c.x)*(b.y-a.y)));
q.y=((c.x-a.x)*(c.x-b.x)*(b.x-a.x)+(a.y*a.y-b.y*b.y)*(c.x-a.x)-(a.y*a.y-c.y*c.y)*(b.x-a.x))/(2*((c.x-a.x)*(a.y-b.y)-(a.y-c.y)*(b.x-a.x)));
return q;
}
int main()
{
srand(time(NULL));
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
if(n==1||n==2)
{
printf("%lf %lf %lf\n",p[0].x+1,p[0].y,1.0);
continue;
}
if(n==3||n==4)
{
printf("%lf %lf %lf\n",(p[0].x+p[1].x)/2,(p[0].y+p[1].y)/2,dis(p[0],p[1])/2);
continue;
}
while(1)
{
int a=rand()%n;
int b=rand()%n;
int c=rand()%n;
if(a==b||a==c||b==c)
continue;
point p1,p2;
p1.x=p[a].x-p[b].x;
p1.y=p[a].y-p[b].y;
p2.x=p[c].x-p[b].x;
p2.y=p[c].y-p[b].y;
if(fabs(p1.x*p2.y-p1.y*p2.x)<=eps)//考虑到精度的关系double只能保存到小数点后6位,所以如果比这个还小就近似的认为在一条线上了
continue; //顺便记录一下,这是叉积
point po=work(p[a],p[b],p[c]);//找到圆心
double r=dis(p[a],po);//圆心到任意一点就是半径
int sum=0;
for(int i=0; i<n; i++)//用该圆对每个点比较一下,看是否在圆上
{
if(fabs(dis(p[i],po)-r)<=eps)//依然是因为精度关系,如果比1e-6还小就近似认为在圆上了
sum++;
}
if(2*sum>=n)
{
printf("%lf %lf %lf\n",po.x,po.y,r);
break;
}
}
}
return 0;
}