题目大意:给一个点,一个圆和一个矩形,矩形与圆没有重叠部分,点也在圆和矩形外,求从该点出发经过圆上一点再到矩形边上一点的距离和的最小值。
思路:三分角度求最小距离和。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
const int maxn=1000+5;
const int inf=1e9;
const ll mod=1e9+7;
const double pi=acos(-1.0);
struct point{
double x,y;
point(){}
point (double _x,double _y){
x=_x;y=_y;
}
point operator-(const point &ne)const{
return point (x-ne.x,y-ne.y);
}
point operator+(const point &ne)const{
return point (x+ne.x,y+ne.y);
}
point operator*(const double t)const{
return point (x*t,y*t);
}
};
struct line{
point a,b;
line (){}
line(point _a,point _b){a=_a;b=_b;}
};
struct circle{
point O;
double r;
};
double dmult(point a,point b){
return a.x*b.x+a.y*b.y;
}
inline double lenth(point a){
return sqrt(dmult(a,a));
}
inline double dist(point a,point b){
return lenth(b-a);
}
inline double dist2(point a,point b){
return dmult(b-a,b-a);
}
double relation(point p,line l){
line t1(l.a,p);
return dmult(t1.b-l.a,l.b-l.a)/dist2(l.a,l.b);
}
point perpend(point p,line l){
double r=relation (p,l);
return l.a+((l.b-l.a)*r);
}
double distoline(point p,line l){
double r=relation(p,l);
if(r<0){
return dist(p,l.a);
}
if(r>1)return dist(p,l.b);
point np=perpend(p,l);
return dist(p,np);
}
const double eps=1e-9;
double sx,sy;
double x,y,r;
circle cir;
point start;
point P[4];
line L[4];
double cal(double alpha){
double x,y;
x=cir.O.x+cir.r*cos(alpha);
y=cir.O.y+cir.r*sin(alpha);
double res=1e18;
point pp=point(x,y);
double tmp=dist(pp,start);
for(int i=0;i<4;i++){
res=min(res,distoline(pp,L[i]));
}
return res+tmp;
}
double Solve(double leftvale,double rightvale) { //三分{
double Left, Right;
double mid, midmid;
double mid_value, midmid_value;
Left = leftvale; Right = rightvale;
while (Left + eps< Right)
{
//mid = (Left + Right) / 2;
mid=Left+(Right-Left)/3;
midmid = Right-(Right-Left)/3;
mid_value = cal(mid);
midmid_value = cal(midmid);
// 假设求解最xiao极值.
if (mid_value < midmid_value) Right = midmid;
else Left = mid;
}
return cal(Left);
}
int main()
{
while(scanf("%lf%lf",&sx,&sy)!=EOF){
if(sx==0&&sy==0)break;
start.x=sx;start.y=sy;
scanf("%lf%lf%lf",&x,&y,&r);
cir.O.x=x;cir.O.y=y;cir.r=r;
double X1,Y1,X2,Y2;
scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);
P[0].x=X1;P[0].y=Y1;
P[1].x=X1;P[1].y=Y2;
P[2].x=X2;P[2].y=Y2;
P[3].x=X2;P[3].y=Y1;
L[0]=line(P[0],P[1]);
L[1]=line(P[1],P[2]);
L[2]=line(P[2],P[3]);
L[3]=line(P[3],P[0]);
double ans=min(Solve(0,pi),Solve(pi,2*pi));
printf("%.2f\n",ans);
}
return 0;
}