【HDU5733 2016 Multi-University Training Contest 1K】【計算幾何 公式做法】tetrahedron 四面體內切球圓心與半徑
阿新 • • 發佈:2019-02-10
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 cases≤100).
Each test cases contains a line of 12 integers[
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) 【資料】 */