2018icpc EC-final F gym102056

题意:

给你一个实心球的球心+R 给出S、T两点在三维空间的坐标 问你S走到T的最短距离

思路

1.dis_st == 0.0

2.∠S或∠T >= pi/2 说明直线必定不与球相交 

3.O到ST的距离H >= R 也不相交

4.常规相交:分别求出S、T与球相切这段的距离(勾股定理)、求出绕球(圆切面)的弧线距离 L = π R

这里求弧度需要用到余弦定理 求H:正弦定理面积= H*L

上代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
 
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
 
double R;
struct Point{
	double x,y,z;
	Point(double x = 0,double y = 0,double z = 0) : x(x),y(y),z(z) {}
}O,S,T;

double dis2(Point A,Point B){
	return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z);
}

double calR(double a,double b,double c){//余弦定理求∠的弧度
	return acos((a + b - c) / (2.0*sqrt(a*b)));
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
		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,&T.x,&T.y,&T.z);
		double dis2_st = dis2(S,T);
		double dis2_ot = dis2(O,T);
		double dis2_os = dis2(S,O);
		//ST == 0
		if(dis2_st == 0.0){
			printf("%.9f\n",0.0);
			continue;
		}
		//如果存在∠OST||∠OTS >= pi/2 则ST一定与球不相交
		double J_S = calR(dis2_st,dis2_os,dis2_ot);
		double J_T = calR(dis2_st,dis2_ot,dis2_os);
		if(J_S >= pi/2.0 || J_T >= pi/2.0){
			printf("%.9f\n",sqrt(dis2_st));
			continue;
		}
		//O到ST的距离>=R ans = ST
		double H = sqrt(dis2_os) * sqrt(dis2_ot) * sin(pi - J_S - J_T) / sqrt(dis2_st);
		if(H >= R){
			printf("%.9f\n",sqrt(dis2_st));
			continue;
		}

		double ss = sqrt(dis2_os - R * R);
		double tt = sqrt(dis2_ot - R * R);
		double sss = acos(R / sqrt(dis2_os));
		double ttt = acos(R / sqrt(dis2_ot));
		double Y = R * (pi - J_S - J_T - sss - ttt);//L = πR
		printf("%.9f\n",ss + tt + Y);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值