ps:虽然是第一次做计算几何,但是还是
了开心。(虽然罚时多了点
)
题目链接:
http://codeforces.com/gym/102056/problem/F
题面:
题意:
给定三维空间的一个起点 终点 和一个 为球心的球,问 到 的最短距离,不能穿过球,可以沿着球面走。
思路:
思路出的很快,就是考虑线段与球相交与否,如果不相交,显然就是线段长度,相交的话考虑切线和切点构成的弧长,具体情况有下面三种:
前两种答案就是线段长度,后面那种就是
。
当然要是只是判断球心到直线距离
就是线段与球相交(这里是线段不是直线!!)那你就会像我一样:
还存在着这样一种:线段和球没有交点但是
,因为这里的
是球到直线的距离。
这种情况也就是
,特判一下就好。(具体看代码)
还是不知道为啥点到线段距离不行,回头修修板子。
参考代码:
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const double pi = acos(-1);
const double eps=1e-6;
int sgn(double x) {
if(fabs(x)<eps)return 0;
if(x<0)return -1;
return 1;
}
struct Point {
double x,y,z;
Point(double x=0,double y=0,double z=0):x(x),y(y),z(z) {}
double dis(const Point& b)const {
return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y)+(z-b.z)*(z-b.z));
}
double len() {
return sqrt(x*x+y*y+z*z);
}
Point operator ^(const Point &b)const { //叉乘
return Point(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);
}
Point operator -(const Point &b)const {
return Point(x-b.x,y-b.y,z-b.z);
}
bool operator ==(const Point &b)const {
return sgn(x-b.x)==0 && sgn(y-b.y)==0 && sgn(z-b.z)==0;
}
double operator *(const Point &b)const {
return x*b.x+y*b.y+z*b.z;
}
double cross(Point b,Point a) { //计算角度
return b.x*a.y-b.y*a.x;
}
double dis_z(Point s,Point e) { //点到直线距离
return ((e-s)^(Point(x,y,z)-s)).len()/s.dis(e);
}
double dis_x(Point s,Point e) { //点到线段距离
if(sgn((Point(x,y,z)-s)*(e-s))>=0&&sgn((Point(x,y,z)-e)*(s-e))>=0)return fabs(cross(Point(x,y,z)-s,e-s))/(e-s).len();
return min((Point(x,y,z)-s).len(),(Point(x,y,z)-e).len());
}
};
double jd(double a,double b,double c) {
return acos((a*a+b*b-c*c)/(2*a*b));
}
int main() {
int t;
scanf("%d",&t);
while(t--) {
double r;
Point s,e,o;
scanf("%lf%lf%lf%lf",&o.x,&o.y,&o.z,&r);
scanf("%lf%lf%lf%lf%lf%lf",&s.x,&s.y,&s.z,&e.x,&e.y,&e.z);
double se=s.dis(e);
double ro=o.dis_z(s,e);
double so=s.dis(o);
double eo=e.dis(o);
//printf("ro:%lf\n",ro);
if(s==e) {
printf("%.8f\n",0.0);
} else if(sgn(ro-r)>=0 || jd(so,se,eo)>=(pi/2)||jd(eo,se,so)>=(pi/2) ) {
printf("%.8f\n",se);
} else {
double sx=sqrt(so*so-r*r);
double ex=sqrt(eo*eo-r*r);
double ans=0.0;
double sox=jd(so,r,sx);
double eox=jd(eo,r,ex);
double soe=jd(so,eo,se);
double ans_=soe-sox-eox;
ans=ans_*r;
printf("%.8f\n",sx+ex+ans);
}
}
return 0;
}
/*
10
10 10 10 1
1 2 1 2 7 3
*/