1. 程式人生 > >【HDU5733 2016 Multi-University Training Contest 1K】【計算幾何 公式做法】tetrahedron 四面體內切球圓心與半徑

【HDU5733 2016 Multi-University Training Contest 1K】【計算幾何 公式做法】tetrahedron 四面體內切球圓心與半徑

tetrahedron

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 723    Accepted Submission(s): 294


Problem Description Given four points ABCD, if ABCD is a tetrahedron, calculate the inscribed sphere of ABCD.
Input Multiple test cases (test cases100).

Each test cases contains a line of 12 integers[
1e6,1e6]
indicate the coordinates of four vertices of ABCD.

Input ends by EOF.

Output Print the coordinate of the center of the sphere and the radius, rounded to 4 decimal places.

If there is no such sphere, output "O O O O".

Sample Input 0 0 0 2 0 0 0 0 2 0 2 0 0 0 0 2 0 0 3 0 0 4 0 0
Sample Output 0.4226 0.4226 0.4226 0.4226 O O O O
Author HIT
Source
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
const double eps = 1e-6;
//既可以定義為點,又可以定為為向量
struct Point
{
	LL x, y, z;
	Point(LL x = 0, LL y = 0, LL z = 0) :x(x), y(y), z(z) {};
	bool input()
	{
		return ~scanf("%lld%lld%lld", &x, &y, &z);
	}
	Point operator - (Point &b)const
	{
		return Point(x - b.x, y - b.y, z - b.z);
	}
	Point operator * (Point &b)const
	{
		return Point(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x);
	}
	double length()
	{
		return sqrt(x*x + y*y + z*z);
	}
}p[4];

//已知四面體的6條稜長,求出四面體體積
double volume(double l, double n, double a, double m, double b, double c)
{
	double x, y;
	x = 4 * a * a * b * b * c * c - a * a * (b * b + c * c - m * m) * (b * b + c * c - m * m) - b * b * (c * c + a * a - n * n) * (c * c + a * a - n * n);
	y = c * c * (a * a + b * b - l * l) * (a * a + b * b - l * l) - (a * a + b * b - l * l) * (b * b + c * c - m * m) * (c * c + a * a - n * n);
	return sqrt(x - y) / 12;
}

//已知三角形邊長,求出三邊形面積
double S(double a, double b, double c)
{
	double p = (a + b + c) / 2;
	return sqrt(p * (p - a) * (p - b) * (p - c));
}

double d[4][4];	//求兩點之間的距離
double s[4];	//求該點所對平面的面積
int main()
{
	while (p[0].input(), p[1].input(), p[2].input(), p[3].input())
	{
		for (int i = 0; i < 4; ++i)
		{
			for (int j = i + 1; j < 4; ++j)d[i][j] = d[j][i] = (p[j] - p[i]).length();
		}
		double vol = volume(d[0][1], d[0][2], d[0][3], d[1][2], d[1][3], d[2][3]);
		double area = 0;
		for (int i = 0; i < 4; ++i)
		{
			vector<double>vt;
			for (int j = 0; j < 4; ++j)if (j != i)
			{
				for (int k = j + 1; k < 4; ++k)if (k != i)vt.push_back(d[j][k]);
			}
			s[i] = S(vt[0], vt[1], vt[2]);
			area += s[i];
		}
		if (fabs(vol) < eps || fabs(area) < eps)puts("O O O O");
		else
		{
			double x = 0; for (int i = 0; i < 4; ++i)x += s[i] * p[i].x; x /= area;
			double y = 0; for (int i = 0; i < 4; ++i)y += s[i] * p[i].y; y /= area;
			double z = 0; for (int i = 0; i < 4; ++i)z += s[i] * p[i].z; z /= area;
			double r = vol * 3 / area;
			printf("%.4f %.4f %.4f %.4f\n", x, y, z, r);
		}
	}
	return 0;
}
/*
【題意】
給你四個點。
讓你求四個點是否共面,不共面的話,求出其內切球的球心以及半徑。

【型別】
計算幾何

【分析】
這題我直接二話不說,
寫了一個三分套三分套三分。
但是常數巨大於是TLE了。
還是推公式靠譜。
首先,我們求出該四面體的6條稜長和4個面積之後,
6條稜長可以直接求出四面體體積。
然後(體積*3)/面積之和,就是其內切球的半徑。
內切球的圓心公式,有一種非常美的表現形式——
double x = 0; for (int i = 0; i < 4; ++i)x += s[i] * p[i].x; x /= area;
double y = 0; for (int i = 0; i < 4; ++i)y += s[i] * p[i].y; y /= area;
double z = 0; for (int i = 0; i < 4; ++i)z += s[i] * p[i].z; z /= area;
double r = vol * 3 / area;
printf("%.4f %.4f %.4f %.4f\n", x, y, z, r);

即4個點(三維座標*對面面積)關於總面積的加權平均值。
其實,這個可以是由三角形的內切圓推廣而來
內切圓的圓心,
是3個點(三維座標*對邊邊長)關於總邊長的加權平均值。

【時間複雜度&&優化】
O(1)

【資料】


*/