博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[poj][3285][Point of view in Flatland]

Posted on 2012-07-12 17:35  紫华弦筝  阅读(236)  评论(0编辑  收藏  举报

题目:http://poj.org/problem?id=3285

题意:求一个与三个圆的角直径都相等并且最大的点的位置。即为求一个点,使这个点到三个圆的距离与该圆的距离之比相等。用方差的方法来进行评估随机化的结果。然后注意要确保点在范围内。

View Code
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <algorithm>

#define dis(a,b) sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))
using namespace std;

const double pi = acos(-1.0);
const double eps = 1e-8;
const double M = 1e99;

double xx, yy, ag, e, ne, mx, my, nx, ny;
struct circle{
    double x, y, r;
    circle(){}
    circle(double x, double y):x(x),y(y){}
    void get(){ scanf("%lf%lf%lf", &x,&y,&r); xx+=x,yy+=y;}
    bool zero() { return x==0&&y==0&&r==0; }
}c[3];

void init(){
    srand(time(NULL));
    mx=-M, my=-M, nx=M, ny=M;
    for (int i=0; i<3; i++){
        mx = max(mx, c[i].x), my = max(my, c[i].y);
        nx = min(nx, c[i].x), ny = min(ny, c[i].y);
    }
    ag = max(mx-nx, my-ny);
}

double cal(circle tmp){
    if (tmp.x < nx || tmp.x > mx) return 1e99;
    if (tmp.y < ny || tmp.y > my) return 1e99;
    double r[3], a=0, ans=0;
    for (int i=0; i<3; i++)
        r[i] = c[i].r / dis(tmp,c[i]), a+=r[i];
    for (int i=0; i<3; i++)
        ans += (r[i]-a/3)*(r[i]-a/3);
    return sqrt(ans/3);
}
int main(){
    //freopen("D:/a.txt", "r", stdin);
    while (true){
        xx = yy = 0;
        for (int i=0; i<3; i++) c[i].get();
        if (c[0].zero()&&c[1].zero()&&c[2].zero()) break;
        circle p(xx/3,yy/3);
        e = cal(p);
        init();
        for (double t=ag; t>eps; t*=0.88){
            for (int k=0; k<20; k++){
                double delta = rand();
                circle tmp(p.x+cos(delta)*t,p.y+sin(delta)*t);
                ne = cal(tmp);
                if (e > ne) p=tmp, e=ne;
            }
        }
        if(e<eps) printf("%.2f %.2f\n", p.x, p.y);
        else printf("No solution\n");
    }
    return 0;
}