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

ps:雖然是第一次做計算幾何,但是還是acac了開心。(雖然罰時多了點OrzOrz

題目鏈接:

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

題面:

在這裏插入圖片描述

題意:

給定三維空間的一個起點ss終點ee和一個oo爲球心的球,問ssee的最短距離,不能穿過球,可以沿着球面走。

思路:

思路出的很快,就是考慮線段與球相交與否,如果不相交,顯然就是線段長度,相交的話考慮切線和切點構成的弧長,具體情況有下面三種:

在這裏插入圖片描述
前兩種答案就是線段長度,後面那種就是sx+xx+exsx+弧xx+ex
當然要是隻是判斷球心到直線距離?dr?d \leq r就是線段與球相交(這裏是線段不是直線!!)那你就會像我一樣:
在這裏插入圖片描述
還存在着這樣一種:線段和球沒有交點但是drd \leq r,因爲這裏的dd是球到直線的距離。
在這裏插入圖片描述
這種情況也就是eso90seo90\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
*/
發佈了305 篇原創文章 · 獲贊 222 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章