题目描述
牛能在家里遇到了一个问题,他现在想要去找牛可乐并向他请教这个问题,现在他已经知道了牛可乐家的坐标,并且他很容易找到了通往牛可乐家里的最短路(一条直线)。
但是,平面上有一个圆形区域,这个圆形区域内是被诅咒过的地方,所以牛能不能进入这块圆形区域的内部,所以牛能现在找不到通往牛可乐家的最短路了,请帮助他解决这个问题!
保证牛能家和牛可乐家不在诅咒区域内。
输入描述:
第一行四个整数 x1, y1, x2, y2x1,y1,x2,y2,(x1, y1)(x1,y1) 表示牛能家的坐标,(x2, y2)(x2,y2) 表示牛可乐家的坐标。
第二行三个整数 x3, y3, rx3,y3,r,(x3, y3)(x3,y3) 表示被诅咒的圆形区域的位置的圆心坐标,rr 表示这个圆形区域的半径。
输出描述:
在一行中输出牛能从家到牛可乐家的最短路。
示例1
输入
-1 -1 1 1
0 0 1
输出
3.570796
示例2
输入
1 1 2 2
0 0 1
输出
1.414214
备注:
−
1
e
5
<
=
x
1
,
y
1
,
x
2
,
y
2
,
x
3
,
y
3
<
=
1
e
5
,
1
<
=
r
<
=
1
e
5
-1e^{5}<=x1,y1,x2,y2,x3,y3<=1e^{5},1<=r<=1e^{5}
−1e5<=x1,y1,x2,y2,x3,y3<=1e5,1<=r<=1e5
如果标准答案是
a
a
a,你的答案是
b
b
b
当满足
f
a
b
s
(
a
−
b
)
m
a
x
(
1.0
,
f
a
b
s
(
a
)
≤
1
0
−
6
\frac{fabs(a-b)}{max(1.0,fabs(a)}\leq10^{-6}
max(1.0,fabs(a)fabs(a−b)≤10−6你的答案被认为是正确的。
Solution
- 首先判断两点连成的直线是否与圆相交,使用
点积正负
以及圆心到直线距离
这两种方法判断,直线与圆不相交
的情况下最短路为两点之间直线距离。 - 当两点直线与圆相交时,最短距离为两点与圆
切线
的长度,加上圆上两个切点之间的弧长
(后续画个图演示一下吧)
#include <bits/stdc++.h>
#define LINF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
static const int N=5e2+5;
const double eps=1e-6;
const ll mod=1e9+7;
double R;
struct Point{
double x,y;
}p[3];
double dis(Point p1,Point p2){ //两点距离
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
double Dot(Point p1,Point p2,Point p3){ //点积
return (p2.x-p1.x)*(p2.x-p3.x)+(p2.y-p1.y)*(p2.y-p3.y);
}
bool check(Point p1,Point p2,Point p3){ //判断点积是否为负
return Dot(p1,p2,p3)<=0||Dot(p2,p1,p3)<=0; // >=90°
}
double judge(Point p1,Point p2,Point p3){
double a=dis(p1,p2),b=dis(p1,p3),c=dis(p2,p3);
double p=(a+b+c)/2;
double S=sqrt(p*(p-a)*(p-b)*(p-c)); //海伦公式求面积
return (2*S/a)>=R; //判断点到直线距离是否大于R
}
double ang(Point p1,Point p2,Point p3){
double a=dis(p1,p2),b=dis(p1,p3),c=dis(p2,p3);
return acos((b*b+c*c-a*a)/(2*b*c)); //余弦公式求acos
}
int main(){
for(int i=0;i<3;++i) scanf("%lf%lf",&p[i].x,&p[i].y);
scanf("%lf",&R);
if(check(p[0],p[1],p[2])||judge(p[0],p[1],p[2])){
printf("%.6f\n",dis(p[0],p[1]));
return 0;
}
double d13=dis(p[0],p[2]),d12=dis(p[0],p[1]),d23=dis(p[1],p[2]);
double d1=sqrt(d13*d13-R*R),d2=sqrt(d23*d23-R*R);
double d3=R*(ang(p[0],p[1],p[2])-acos(R/d13)-acos(R/d23));
printf("%.6f\n",d1+d2+d3);
return 0;
}