HDU 6097 Mindis(计算几何)

来源:互联网 发布:鬼魂探测器软件 编辑:程序博客网 时间:2024/06/06 01:41

原题链接

Problem Description

The center coordinate of the circle C is O, the coordinate of O is (0,0) , and the radius is r.
P and Q are two points not outside the circle, and PO = QO.
You need to find a point D on the circle, which makes PD+QD minimum.
Output minimum distance sum.

Input

The first line of the input gives the number of test cases T; T test cases follow.
Each case begins with one line with r : the radius of the circle C.
Next two line each line contains two integers x , y denotes the coordinate of P and Q.

Limits
T≤500000
−100≤x,y≤100
1≤r≤100

Output

这里写图片描述

Sample Input

4
4
4 0
0 4
4
0 3
3 0
4
0 2
2 0
4
0 1
1 0

Sample Output

5.6568543
5.6568543
5.8945030
6.7359174

题目大意

给一个圆和园内的两个点,保证这两个点与圆心的距离相同,现要在圆上找到一个点使得圆上的点与给出的两个点的距离和最小。

解题思路

引用官方题解。这题有个坑就是给出的两个点有可能重合。其他问题不大。

很不幸不总是中垂线上的点取到最小值,考虑点在圆上的极端情况。
做P点关于圆的反演点P’,OPD与ODP’相似,相似比是|OP| : r。

Q点同理。

极小化PD+QD可以转化为极小化P’D+Q’D。

当P’Q’与圆有交点时,答案为两点距离,否则最优值在中垂线上取到。

时间复杂度 O(1)

也有代数做法,结论相同。

优秀的黄金分割三分应该也是可以卡过的。

AC代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<algorithm>#include<cmath>#include<vector>#include<string>#include<queue>#include<list>#include<stack>#include<set>#include<map>#define ll long long#define ull unsigned long long#define db double//#define rep(i,n) for(int i = 0;i < n; i++)#define rep(i,a,b) for(int i=(a);i<(b);++i)#define fil(a,b) memset((a),(b),sizeof(a))#define cl(a) fil(a,0)#define pb push_back#define mp make_pair#define exp 2.7182818#define PI 3.141592653589793#define inf 0x3f3f3f3f#define fi first#define se second#define eps 1e-8#define MOD 1000000007ll#define sign(x) ((x)>eps?1:((x)<-eps?(-1):(0)))struct point2{    double x,y;    point2(){}    point2(double _x,double _y)    {        x=_x,y=_y;    }    point2 operator-(const point2 &ne)    {        return point2(x-ne.x,y-ne.y);    }    point2 operator+(const point2 &ne)    {        return point2(x+ne.x,y+ne.y);    }    point2 operator*(const double t)    {        return point2(x*t,y*t);    }};struct line2{    point2 a,b;    line2(){}    line2(point2 _a,point2 _b)    {        a=_a;        b=_b;    }};double dmult(point2 a,point2 b){    return a.x*b.x+a.y*b.y;}double xmult(point2 a,point2 b){     return a.x*b.y-a.y*b.x; } double xmult(point2 o,point2 a,point2 b) {     return (a.x-o.x)*(b.y-o.y)-(b.x-o.x)*(a.y-o.y); } double xmult(double x1,double y1,double x2,double y2) {     return x1*y2-x2*y1; }double xmult(line2 x,line2 y){ return xmult(x.b-x.a,y.b-y.a); }double length(point2 v){    return sqrt(v.x*v.x+v.y*v.y);}double dist(point2 a,point2 b){    return length(a-b);}double dist2(point2 a,point2 b){    return dmult(a-b,a-b);}using namespace std;double mysqrt(double x) { return max(0.0, sqrt(x)); }int sgn(double x){    if(fabs(x) < eps) return 0;    if(x < 0)return -1;    else return 1;}bool equal(double a,double b){    if(abs(a-b)<eps) return true;    else return false;}int main() {    int t;    double r;    point2 p,q,pp,qq;    cin>>t;    while(t--)    {        scanf("%lf",&r);        scanf("%lf%lf%lf%lf",&p.x,&p.y,&q.x,&q.y);        if(p.x==p.y&&equal(0,p.x))        {            printf("%.8f\n",2*r);        }        else if(p.x==q.x&&p.y==q.y)        {            printf("%.8f\n",2*(r-length(p)));        }        else        {        double ratio=r/length(p);        pp.x=p.x*ratio*ratio;        pp.y=p.y*ratio*ratio;        qq.x=q.x*ratio*ratio;        qq.y=q.y*ratio*ratio;        //pp,qq为反演点        double distoo=abs(xmult(pp,qq)/dist(pp,qq));        if(distoo-r>-eps) //中垂线        {            if(equal(p.y,q.y))            {                point2 p1=point2(0,r);                point2 p2=point2(0,-r);                printf("%.8f\n",min(dist(p1,p)+dist(p1,q),dist(p2,q)+dist(p2,p)));            }            else            {                double k=-(qq.x-pp.x)/(qq.y-pp.y);                double b=(qq.x-pp.x)*(pp.x+qq.x)/(qq.y-pp.y)/2+(pp.y+qq.y)/2;                point2 p1=point2(-(sqrt((k*k+1)*r*r-b*b)+b*k)/(k*k+1),-(k*sqrt(k*k*r*r+r*r-b*b)-b)/(k*k+1));                point2 p2=point2((sqrt((k*k+1)*r*r-b*b)-b*k)/(k*k+1),-(-k*sqrt(k*k*r*r+r*r-b*b)-b)/(k*k+1));                printf("%.8f\n",min(dist(p1,p)+dist(p1,q),dist(p2,p)+dist(p2,q)));            }        }        else //求交点        {            if(equal(p.x,q.x))            {                double xx=pp.x;                point2 p1=point2(xx,sqrt(r*r-xx*xx));                printf("%.8f\n",dist(p1,p)+dist(p1,q));            }            else            {                double k=(pp.y-qq.y)/(pp.x-qq.x);                double b=pp.y-(pp.y-qq.y)*pp.x/(pp.x-qq.x);                point2 p1=point2(-(sqrt((k*k+1)*r*r-b*b)+b*k)/(k*k+1),-(k*sqrt(k*k*r*r+r*r-b*b)-b)/(k*k+1));                printf("%.8f\n",dist(p1,p)+dist(p1,q));            }        }        }    }    return 0;}
原创粉丝点击