Interstellar … Fantasy 题解

题目大意:在一个三维空间中,给定一个球,给定两个点,询问这两个点的最短距离

解体思路:首先我们可以思考这样一种情况,两个点的连线没有经过球,显而易见我们可以想到球心到直线的距离大于半径;但是如果两点都在球的外面,但是球心到直线的距离小于R的时候需要特判,剩下的经过圆的只需要考虑到二维就行了

(因为球的任何一个面都是⚪)

#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
const ld eps = 1e-8;
const ld pi = acos(-1);
int T;
ld ox,oy,oz,r;
ld sx,sy,sz,tx,ty,tz;
ld m,n,p;
ld t;
ld cal(ld xx,ld yy,ld zz,ld xxx,ld yyy,ld zzz)
{
	ld anss = sqrtl((xx - xxx) * (xx - xxx) + (yy - yyy) * (yy - yyy) + (zz - zzz) * (zz - zzz));
	return anss;
}
ld S(ld a,ld b,ld c)
{
    ld p = (a + b + c) / 2;
    return sqrt(p*(p-a)*(p-b)*(p-c));
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%Lf %Lf %Lf %Lf",&ox,&oy,&oz,&r);
		scanf("%Lf %Lf %Lf %Lf %Lf %Lf",&sx,&sy,&sz,&tx,&ty,&tz);
		if(sx == tx && sy == ty && sz == tz)
		{
			printf("0\n");
			continue;
		}
		m = tx - sx;
		n = ty - sy;
		p = tz - sz;
		t = (m * (ox - sx) + n * (oy - sy) + p * (oz - sz)) / (m * m + n * n + p * p);
		//cout << t <<"\n";
		ld dis1 = cal(ox,oy,oz,tx,ty,tz);
		ld dis2 = cal(ox,oy,oz,sx,sy,sz);
		ld crox,croy,croz;
		crox = m * t + sx;
		croy = n * t + sy;
		croz = n * t + sz;
		ld point_dis = cal(sx,sy,sz,tx,ty,tz);
		ld s = S(dis1,dis2,point_dis);
		ld line_dis = 2 * s / point_dis;
		if(line_dis - r >= eps)
		{
			//cout <<"???"<<"\n";
			printf("%.12Lf\n",point_dis);
		} 
		else
		{
			if(dis1 > dis2) swap(dis1,dis2);
			ld cosst;
			cosst = (dis1 * dis1 + point_dis * point_dis - dis2 * dis2) / (2 * dis1 * point_dis);
			if(cosst < 0)
			{
				printf("%.12Lf\n",point_dis);
			}
			else
			{
				ld ans1 = sqrtl(dis1 * dis1 - r * r);
				ld ans2 = sqrtl(dis2 * dis2 - r * r);
				//cout <<"????"<< ans1<<" "<<ans1<<" "<<"\n";
				ld cosst1 = r / dis1;
				ld cosst2 = r / dis2;
				ld cosst3 = (dis1 * dis1 + dis2 * dis2 - point_dis * point_dis) / (2 * dis1 * dis2);
				ld st1 = acos(cosst1);
				ld st2 = acos(cosst2);
				ld st3 = acos(cosst3);
				ld st = st3 - st2 - st1;
				//cout << "st" <<st1<<" "<<st2<<" "<<st3<<"\n"; 
				ld ans3 = st  * r;
				ld ans = ans1 + ans2 + ans3;
				printf("%.12Lf\n",ans);
			}
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值