题目大意:自行百度。
解题策略:
首先判断AB所在直线是否与圆相交:
1,不相交:直接计算AB距离即可。
2,相交:
(1)这里有wa点,还需判断AB线段是否与圆相交,若不想交计算同1;
判断方法:若三角形ABO中角A或角B为钝角,线段与圆不相交;
(2)若AB线段与圆相交,
最终答案:ansL = AD + 弧CD + BC,
第一步:AD,BC由勾股定理求得;
第二步:弧CD = 圆心角COD(弧度制)*半径
第三步:利用余弦定理求出角BOA,,角AOD,角B0C ———— 角COD = 角BOA - 角AOC-角BOC;
由第三步逐步向上操作,既得答案。
3,注意事项:
(1)计算几何一定要细心再细心,尤其是复杂运算,一定要注意;
(2)C/C++三角函数针对弧度制操作,注意必要转换;
/*
UVA 10180 Rope Crisis in Ropeland!
AC by J_Dark
ON 2013/5/14 19:52
Time 0.582s
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-20;
struct p{
double x, y;
void Set(double a, double b){ x = a; y = b;}
double Ditance(p t){
return sqrt( (t.x-x)*(t.x-x) + (t.y-y)*(t.y-y) );
}
}A, B, C, D, O;
double rad, AB, AD, AO, BO, BC;
void Input(){
double x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2 >> rad;
A.Set(x1, y1);
B.Set(x2, y2);
AB = A.Ditance(B);
O.Set(0, 0);
}
bool isSpecialNI(){
AO = A.Ditance(O);
BO = B.Ditance(O);
if(AO*AO + AB*AB - BO*BO < eps || AB*AB + BO*BO - AO*AO < eps)
return true;
return false;
}
double aCos(double a, double b, double c){
return (a*a + b*b - c*c) / (2*a*b); //这个表达式分母忘记加括号,结果调了一下午T-T
}
double compute(){
double BOC, AOD, COD, BOA;
BC = sqrt(BO*BO - rad*rad);
AD = sqrt(AO*AO - rad*rad);
BOA = acos(aCos(BO, AO, AB));
BOC = acos(aCos(BO, rad, BC));
AOD = acos(aCos(AO, rad, AD));
COD = (BOA - BOC - AOD);
return COD*rad + BC + AD;
}
void Solve(){
double AA, BB, CC, dd, ansL;
bool f1;
if(fabs(A.x - B.x) < eps){ //线段斜率不存在
dd = fabs(A.x);
}
else{ //线段斜率存在
AA = (B.y - A.y)/(B.x - A.x);
BB = -1;
CC = A.y - A.x*AA;
dd = fabs(CC/sqrt(AA*AA + BB*BB));
}
if(dd < rad){ //圆与线段所在直线相交
if(isSpecialNI()){ //线段与圆不相交
f1 = false;
}
else{//线段与圆相交 正式进入运算
f1 = true;
ansL = compute();
}
}
else f1 = false;
if(!f1){ //圆与线段不相交
ansL = AB;
}
printf("%.3lf\n", ansL);
}
int main(){
int testCase;
while(cin >> testCase)
{
while(testCase--)
{
Input();
Solve();
}
}
return 0;
}