1. 程式人生 > >HDU 6242 Geometry Problem (隨機數+計算幾何)

HDU 6242 Geometry Problem (隨機數+計算幾何)

Geometry Problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 4362    Accepted Submission(s): 772Special JudgeProblem Description

Alice is interesting in computation geometry problem recently. She found a interesting problem and solved it easily. Now she will give this problem to you : You are given N distinct points (Xi,Yi) on the two-dimensional plane. Your task is to find a point P and a real number R, such that for at least ⌈N2⌉ given points, their distance to point P is equal to R.

Input

The first line is the number of test cases. For each test case, the first line contains one positive number N(1≤N≤105). The following N lines describe the points. Each line contains two real numbers Xi and Yi (0≤|Xi|,|Yi|≤103) indicating one give point. It's guaranteed that Npoints are distinct.

Output

For each test case, output a single line with three real numbers XP,YP,R, where (XP,YP) is the coordinate of required point P. Three real numbers you output should satisfy 0≤|XP|,|YP|,R≤109. It is guaranteed that there exists at least one solution satisfying all conditions. And if there are different solutions, print any one of them. The judge will regard two point's distance as R if it is within an absolute error of 10−3 of R.

Sample Input

1 7 1 1 1 0 1 -1 0 1 -1 1 0 -1 -1 0

Sample Output

0 0 1

Source

題意:給出N個點,讓你確定一個圓,使得至少有ceil(N/2)個點在圓上,輸出這個圓的半徑和圓心座標

思路:題目已經說明肯定會有一個符合條件的圓存在,最多100000個點,至少有50000個點在一個圓上,因為不再同一條直線上的三點確定一條直線,我們任意取三個點,這三個點能確定符合題意的圓的概率為C(3,50000)/C(3,100000),大約1/8,所以隨機去個幾十次肯定能取到符合題意的三個點,隨機取點的過程就用到了隨機數了

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const double eps = 1e-8;
const double inf = 1e20;
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    else return 1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double _x,double _y)
    {
        x = _x;
        y = _y;
    }
    void input()
    {
        scanf("%lf %lf",&x,&y);
    }
    double operator *(const Point &b) const
    {
        return x * b.x + y * b.y;
    }
    Point operator - (const Point &b) const
    {
        return Point(x - b.x,y - b.y);
    }
    Point operator + (const Point &b) const
    {
        return Point(x + b.x,y + b.y);
    }
    Point operator / (const double &k) const
    {
        return Point(x / k,y / k);
    }
    double operator ^ (const Point &b) const
    {
        return x * b.y - y * b.x;
    }
    Point rotleft()
    {
    	return Point(-y,x);
    }
    double distance(Point p) 
    {
    	return hypot(x - p.x,y - p.y);
    }
}p[MAXN];
struct Line
{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e)
    {
        s = _s;
        e = _e;
    }
    bool parallel(Line v)
    {
       return sgn( (e - s) ^ (v.e - v.s) ) == 0;
    }
    Point crosspoint(Line v)
	{
		double a1 = (v.e - v.s) ^ (s - v.s);
		double a2 = (v.e - v.s) ^ (e - v.s);
		return Point((s.x * a2 - e.x * a1) / (a2 - a1), 
		(s.y * a2 - e.y * a1) / (a2 - a1));
	}
};
struct circle
{
	Point p;
	double r;	
	circle(){}
	circle(Point a,Point b,Point c)
	{
		Line u = Line((a + b) / 2,((a + b) / 2) + ((b - a).rotleft()));
		Line v = Line((b + c) / 2,((b + c) / 2) + ((c - b).rotleft()));
		p = u.crosspoint(v);
		r = p.distance(a);
	}
	int relation(Point b)
	{
		double dst = b.distance(p);
		if(sgn(dst - r) < 0) return 2;
		else if(sgn(dst - r) == 0) return 1;
		return 0;
	}
};
int main(void)
{
    int T,n,cnt;
    int a,b,c;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) {
            p[i].input();
        }
        if(n == 1) {
            printf("%f %f %f\n",p[1].x - 1,p[1].y,1.0);
        }
        else if(n > 1 && n <= 4) {
            printf("%f %f %f\n", (p[1].x + p[2].x) * 0.5 , (p[1].y + p[2].y) * 0.5,
                  sqrt( (p[2].x - p[1].x) * (p[2].x - p[1].x) + (p[2].y - p[1].y) * (p[2].y - p[1].y) ) / 2 );
        }
        else {
            while(1) {
                a = rand() % n + 1;
                b = rand() % n + 1;
                c = rand() % n + 1;
                Line L1 = Line(p[a],p[b]);
                Line L2 = Line(p[a],p[c]);
                if(L1.parallel(L2)) {
                	continue;
                }
                cnt = 0;
                circle O = circle(p[a],p[c],p[b]);
                for(int i = 1; i <= n; i++) {
                	if(O.relation(p[i]) == 1) {
                		cnt++;
                	}
                }
                if(cnt >= ceil(n / 2)) {
                	printf("%lf %lf %lf\n",O.p.x,O.p.y,O.r);
                	break;
                } 
            }
        }
    }
    return 0;
}