HDU5733_四面體的內切球
阿新 • • 發佈:2019-01-02
1.前言:2018馬上就要過去了,今天的一場模擬賽做到了這個題,一開始沒有人過,我在隊友開其他題的時候偷懶找了個題面最短的題來做,結果還真讓我yy出來了。其實高數基礎紮實還是很有用的哈。
2.題目連結。題意十分的裸,就是給你空間中四個點求球心的座標以及球的半徑。首先我們需要知道一些東西,半徑怎麼求?這個其實大家高中都會,就是等體積法,四面體的體積被表示成表面積與內切球半徑的乘積的3倍。四面體的體積可以有很多種球法,我們可以使用點到平面的距離,我覺得最簡單的還是混合積的六分之一好算。最後最重要的就是球心座標的計算了。其實也很簡單,就是公式,求出每個點對球心座標的貢獻,這其實是一個加權的平均數,權值就是這個點對的面的面積。為什麼時是這樣的?其實微積分中有答案的,不懂得同學可以翻翻書看看。我直接把我的程式碼拉出來:
#include<iomanip> #include<cmath> using namespace std; struct P { double x, y, z; P() {}; P(double x, double y, double z) { this->x = x; this->y = y; this->z = z; } P operator-(const P a) { return P(a.x - x, a.y - y, a.z - z); } }p[4]; double getA(P a, P b, P c) { double l1 = sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y,2) + pow(a.z - b.z, 2)); double l2 = sqrt(pow(a.x - c.x, 2) + pow(a.y - c.y, 2) + pow(a.z - c.z,2)); double l3 = sqrt(pow(b.x - c.x, 2) + pow(b.y - c.y, 2) + pow(b.z - c.z, 2)); double p = (l1 + l2 + l3) / 2; double s = sqrt(p*(p - l1)*(p - l2)*(p - l3)); return s; } double getV(P a, P b, P c) { double s = abs(a.x*(b.y*c.z - b.z*c.y) - a.y*(b.x*c.z - b.z*c.x) + a.z*(b.x*c.y - b.y*c.x)); return s / 6; } #pragma warning(disable:4996) int main() { while (~scanf("%lf%lf%lf",&p[0].x,&p[0].y,&p[0].z)) { for (int i = 1; i < 4; i++) { cin >> p[i].x >> p[i].y >> p[i].z; } double v = getV(p[0] - p[1], p[0] - p[2], p[0] - p[3]); double s1 = getA(p[0], p[1], p[2]); double s2 = getA(p[0], p[1], p[3]); double s3 = getA(p[0], p[2], p[3]); double s4 = getA(p[1], p[2], p[3]); if (v == 0) { cout << "O O O O" << endl; } else { cout << fixed << setprecision(4); double S = s1 + s2 + s3 + s4; double r = 3 * v / S; double x = (p[0].x*s4 + p[1].x*s3 + p[2].x*s2 + p[3].x*s1) / S; double y = (p[0].y*s4 + p[1].y*s3 + p[2].y*s2 + p[3].y*s1) / S; double z = (p[0].z*s4 + p[1].z*s3 + p[2].z*s2 + p[3].z*s1) / S; cout << x << " " << y << " " << z <<" "<<r<<endl; } } return 0; }
當然了,我當時沒有想這麼多就交了,然後A了,其實隊友說這裡需要加一個eps,我當時驚出一身冷汗,覺得要貢獻出1WA了。雖然僥倖過了,但是出於嚴謹還是需要給每一個數據加上eps,設定成1e-8就OK。