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
*/