2018-2019 ACM-ICPC, Asia East Continent FinalsGym 102056F Interstellar … Fantasy(计算几何)

ps:虽然是第一次做计算几何,但是还是 a c ac 了开心。(虽然罚时多了点 O r z Orz

题目链接:

http://codeforces.com/gym/102056/problem/F

题面:

在这里插入图片描述

题意:

给定三维空间的一个起点 s s 终点 e e 和一个 o o 为球心的球,问 s s e e 的最短距离,不能穿过球,可以沿着球面走。

思路:

思路出的很快,就是考虑线段与球相交与否,如果不相交,显然就是线段长度,相交的话考虑切线和切点构成的弧长,具体情况有下面三种:

在这里插入图片描述
前两种答案就是线段长度,后面那种就是 s x + x x + e x sx+弧xx+ex
当然要是只是判断球心到直线距离 ? d r ?d \leq r 就是线段与球相交(这里是线段不是直线!!)那你就会像我一样:
在这里插入图片描述
还存在着这样一种:线段和球没有交点但是 d r d \leq r ,因为这里的 d d 是球到直线的距离。
在这里插入图片描述
这种情况也就是 e s o 9 0 s e o 9 0 \angle eso \geq 90^\circ 或者\angle seo \geq 90^\circ ,特判一下就好。(具体看代码)
还是不知道为啥点到线段距离不行,回头修修板子。

参考代码:

#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
*/
发布了293 篇原创文章 · 获赞 212 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/nuoyanli/article/details/103479450