HDU 6097 Mindis(计算几何)

原题链接

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;
}

猜你喜欢

转载自blog.csdn.net/xj949967574/article/details/77165196
今日推荐