HDU 4454 计算几何 (三分)

题意 : 给你一个点和一个圆形和一个矩形,让你求这个点先到矩形,再到圆形折线的最小值。
题解 : 我们发现,对于圆上的任意一个点我们都可以求出这个点到这个矩形的最小距离,然后我们就可以通过三分圆上的点找到这个最优解就可以了

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

const double PI = 3.141592653589793;
const double eps = 1e-8;
const double INF = 1e30;
struct point {
    double x,y;
};

struct circle {
    point o;
    double r;
};
struct rec {
    point a,b,c,d;
};
circle c;
point p;
rec fx;

int sgn (double x) {
    if (fabs (x) <= eps) return 0;
    return x > 0 ? 1 : -1;
}
double dist (point a,point b) {
    return sqrt ((a.x - b.x) * (a.x - b.x ) + (a.y - b.y ) * (a.y - b.y));
}

double cross (point a,point b,point c) {
    return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}

double dot (point a,point b,point c) {
    return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y );
}

double dis (point a,point b,point c) {
    if (sgn (dist (a,b)) == 0) return dist (a,c);
    if (dot (a,b,c) < 0) return dist (a,c);
    if (dot (b,a,c) < 0) return dist (b,c);
    double area = fabs (cross (a,b,c));
    return area / dist (a,b);
}

double f (double ang) {
    point temp = c.o;
    temp.x += cos (ang) * c.r;
    temp.y += sin (ang) * c.r;
    double res = dist (temp,p);
    //  printf ("%.3f ",res);
    double rr = INF;
    rr = min (rr,dis (fx.a,fx.b,temp));
    rr = min (rr,dis (fx.b,fx.c,temp));
    rr = min (rr,dis (fx.c,fx.d,temp));
    rr = min (rr,dis (fx.d,fx.a,temp));
    res += rr;
    //  printf ("%.3f\n",res);
    return res;
}

double solve () {
    double l = 0,r = PI;
    double res = INF;
    while (r - l > eps) {
        double mid = (l + l + r) / 3;
        double midd = (l + r + r) / 3;
        if (f(mid) > f(midd)) {
            l = mid;
            res = min (res,f (midd));
        }
        else {
            r = midd;
            res = min (res,f (mid));
        }
    }
    l = PI,r = 2 * PI;
    while (r - l > eps) {
        double mid = (l + l + r) / 3;
        double midd = (l + r + r) / 3;
        if (f(mid) > f(midd)) {
            l = mid;
            res = min (res,f (midd));
        }
        else {
            r = midd;
            res = min (res,f (mid));
        }
    }
    return res;
}

int main () {
    double x,y;
    while(scanf ("%lf%lf",&x,&y) && (sgn(x) || sgn(y))) {
        p.x = x,p.y = y;
        scanf ("%lf%lf%lf",&c.o.x,&c.o.y,&c.r);
        scanf ("%lf%lf%lf%lf",&fx.a.x,&fx.a.y,&fx.c.x,&fx.c.y);
        fx.b.x = fx.a.x,fx.b.y = fx.c.y;
        fx.d.x = fx.c.x,fx.d.y = fx.a.y;
        //  printf ("%.3f %.3f\n",fx.b.x,fx.b.y);
        double ans = solve ();
        printf ("%.2f\n",ans);
    }       
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值