HDU5733 tetrahedron(计算几何)

HDU5733 tetrahedron(计算几何)

本题解由 ljw 提供

题面

题意:给四个点,问是不是四面体,如果是四面体则给出内切球的球心坐标和球的半径。

范围 x , y x, y x,y 坐标 ∈ [ − 1 e 6 , 1 e 6 ] \in [-1e6, 1e6] [1e6,1e6]

分析:判断四个点是否共面即可判断是不是四面体,这里可以利用行列式的值计算(不会的去复习高数下的前几章和线代的相关内容)。

我们令 S = S △ A B C + S △ A B D + S △ A C D + S △ B C D S=S_{\triangle ABC}+S_{\triangle ABD}+S_{\triangle ACD}+S_{\triangle BCD} S=SABC+SABD+SACD+SBCD

则可以得到内切球球心的表达式为:

x = ( S △ A B C ∗ D . x + S △ A B D ∗ C . x + S △ A C D ∗ B . x + S △ B C D ∗ A . x ) S x=(\frac{S_{\triangle ABC}*D.x+S_{\triangle ABD}*C.x+S_{\triangle ACD}*B.x+S_{\triangle BCD}*A.x)}{S} x=(SSABCD.x+SABDC.x+SACDB.x+SBCDA.x)

y = ( S △ A B C ∗ D . y + S △ A B D ∗ C . y + S △ A C D ∗ B . y + S △ B C D ∗ A . y ) S y=(\frac{S_{\triangle ABC}*D.y+S_{\triangle ABD}*C.y+S_{\triangle ACD}*B.y+S_{\triangle BCD}*A.y)}{S} y=(SSABCD.y+SABDC.y+SACDB.y+SBCDA.y)

z = ( S △ A B C ∗ D . z + S △ A B D ∗ C . z + S △ A C D ∗ B . z + S △ B C D ∗ A . z ) S z=(\frac{S_{\triangle ABC}*D.z+S_{\triangle ABD}*C.z+S_{\triangle ACD}*B.z+S_{\triangle BCD}*A.z)}{S} z=(SSABCD.z+SABDC.z+SACDB.z+SBCDA.z)

(具体证明可以去找高中竞赛教辅)

之后即可利用内切球心到四面体的距离相等,利用四个面的面积和整个四面体的体积即可得到球的半径。( r ∗ S = S △ A B C ∗ h r*S = S_{\triangle ABC}*h rS=SABCh h h h D D D S △ A B C S_{\triangle ABC} SABC的距离)

Notice:不存在的时候输出为四个O,不是0

Code

#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
struct Point{
	double x, y, z;
	Point(double x,double y,double z):x(x),y(y),z(z){}
	Point(){
	}
}point[4];
// 判断是否共面
int judge(Point point[])
{
	double x[4], y[4], z[4];
	for(int i = 1; i < 4; i++){
		x[i] = point[i].x - point[0].x;
		y[i] = point[i].y - point[0].y;
		z[i] = point[i].z - point[0].z;
	}
	return (x[1] * y[2] * z[3]) + (x[2] * y[3] * z[1]) + (x[3] * y[1] *z[2]) - (x[3] * y[2] * z[1]) - (y[3] * z[2] * x[1]) - (z[3] * x[2] * y[1]);
}
double dis(Point a, Point b){
	return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) + pow(a.z - b.z, 2));
}
// 海伦公式
double area(Point a, Point b, Point c){
	double ab = dis(a, b);
	double ac = dis(a, c);
	double bc = dis(b, c);
	double p = (ab + ac + bc) / 2;
	return sqrt(p * (p - ab) * (p - ac) * (p - bc));
}
// 球心坐标
vector<double> cal(Point point[])
{
	vector <double> ans;
	ans.resize(3);
	for(int i = 0; i < 3; i++){
		for(int j = 0; j < 4; j++){
			switch(i){
				case 0:
					ans[i] += area(point[(j + 1) % 4], point[(j + 2) % 4], point[(j + 3) % 4]) * point[j].x; break;
				case 1:
					ans[i] += area(point[(j + 1) % 4], point[(j + 2) % 4], point[(j + 3) % 4]) * point[j].y; break;
				case 2:
					ans[i] += area(point[(j + 1) % 4], point[(j + 2) % 4], point[(j + 3) % 4]) * point[j].z; break;
			}
		}
	}
	return ans;
}
Point Cross(Point a, Point b)
{    
	return Point((a.y * b.z - a.z * b.y), -(a.x * b.z - b.x * a.z), (a.x * b.y - a.y * b.x));
}
double Dot(Point A, Point B)
{    
	return (A.x * B.x + A.y * B.y + A.z * B.z);
} 
int main()
{
	while(~scanf("%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", &point[0].x, &point[0].y, &point[0].z, &point[1].x, &point[1].y, &point[1].z, &point[2].x, &point[2].y, &point[2].z, &point[3].x, &point[3].y, &point[3].z)){
		if(judge(point)){
			vector<double> ans = cal(point);
			double S = 0;
			for(int j = 0; j < 4; j++){
				S += area(point[(j + 1) % 4], point[(j + 2) % 4], point[(j + 3) % 4]);
			}
			Point n = Cross(Point(point[0].x - point[1].x, point[0].y - point[1].y, point[0].z - point[1].z), Point(point[2].x - point[1].x, point[2].y - point[1].y, point[2].z - point[1].z));
			
			Point AD = Point(point[0].x - point[3].x, point[0].y - point[3].y, point[0].z - point[3].z);
			//printf("%lf %lf %lf\n", n.x, n.y, n.z);
			double h = fabs(Dot(AD, n) / sqrt(Dot(n, n)));
			double s = area(point[0], point[1], point[2]);
			//printf("%f %f %f\n", s, S, h);
			printf("%.4f %.4f %.4f %.4f\n", ans[0] / S, ans[1] / S, ans[2] / S, s * h / S);
		} else {
			puts("O O O O");
		}
	}
	return 0;
}

【END】感谢观看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值