题目大意给出一个点和一个圆和一个矩形,求一个点先到圆再到矩形的最短路径
可以枚举圆上的一点,然后求该点到矩形的最短距离。
圆上一点关于最短路在[0,Pi] and [pi,2*pi]两个区间上都是单峰函数,所以可以三分法求极值。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define PI 3.1415926
using namespace std;
struct Point
{
double x,y;
Point(double X,double Y)
{
x= X; y = Y;
}
Point operator-(const Point a)
{
return Point(x-a.x,y-a.y);
}
double operator^(const Point a)
{
return (x*a.y-y*a.x);
}
double operator*(const Point a)
{
return (x*a.x+y*a.y);
}
};
double X,Y,R,X1,X2,Y1,Y2;
Point O(0,0);
double Sqrt(double x){ return (x<1e-8?0:sqrt(x));}
double Sqr(double x) { return x*x;}
double dis(Point a, Point b)
{
return (sqrt(Sqr(a.x-b.x)+Sqr(a.y-b.y)));
}
int sign(double x)
{
if (x>1e-8) return 1; else
if (x<-1e-8) return -1;else
return 0;
}
double getDisLine(Point a,Point b,Point c)
{
double ans = dis(a,b);
ans = min(ans,dis(a,c));
if (sign((c-b)*(a-b))>=0 && sign((b-c)*(a-c))>=0)
ans = min(ans,fabs((c-a)^(b-a))/dis(c,b));
return ans;
}
double getDis(Point p)
{
double len = dis(O,p);
Point P1(X1,Y1);
Point P2(X1,Y2);
Point P3(X2,Y1);
Point P4(X2,Y2);
double d= getDisLine(p,P1,P2);
d = min(d,getDisLine(p,P2,P4));
d = min(d,getDisLine(p,P4,P3));
d = min(d,getDisLine(p,P3,P1));
return d+len;
}
double Get(double l, double r)
{
double ans = -1;
while (r-l>=1e-8)
{
double mid1= l+(r-l)/3;
double mid2= r-(r-l)/3;
Point P1 = Point(X+R*cos(mid1),Y+R*sin(mid1));
Point P2 = Point(X+R*cos(mid2),Y+R*sin(mid2));
double len1 = getDis(P1);
double len2 = getDis(P2);
if (ans== -1 || ans>min(len1,len2)) ans = min(len1,len2);
if (len1<len2) r= mid2; else l = mid1;
}
return ans;
}
int main()
{
while (cin>>O.x>>O.y && !(O.x==0 && O.y==0))
{
cin>>X>>Y>>R;
cin>>X1>>Y1>>X2>>Y2;
double ans = Get(0,PI);
ans = min(ans,Get(PI,2*PI));
printf("%.2lf\n",ans);
}
return 0;
}