2017-03-18 HDU 5733 计算几何 codeforces 599E 状压dp(待补)

HDU 5733

题意:给出四面体的四个顶点,求出其内切球的球心坐标和半径,如果不存在内切球,输出"O O O O"。

tags:一堆公式。。可以做模板了

我们可以将平面上的四点得到由同一个点出发的三个矢量。这样就可以计算这三个矢量的混合积M,则M/6即为四面体体积V。

题目无解的情况当且仅当四点共面,即混合积为0。

求得四面体体积后,可以根据公式r = 3V/(S1+S2+S3+S4)得到内切球半径, S1~S4为四面体四个面的面积。

当前的问题转化为如何求四面体四个面的面积。

由于我们已经知道四个顶点的坐标,因此可以通过海伦公式来分别求解四个面的面积S1~S4,以此来求得r。

对于球心坐标,有公式:

x=(p1.x*s1+p2.x*s2+p3.x*s3+p4.x*s4)/(s1+s2+s3+s4);

y=(p1.y*s1+p2.y*s2+p3.y*s3+p4.y*s4)/(s1+s2+s3+s4);

z=(p1.z*s1+p2.z*s2+p3.z*s3+p4.z*s4)/(s1+s2+s3+s4);

si为pi做顶点时,对应的底面的面积。

// HDU 5733 
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 200005;
const double eps=1e-8;

double s[4], sum, x, y, z, v;

struct Point {
    double x, y, z;
    Point operator - (const Point &b) const {    //向量 a 与 b 的点积 
        return Point{x-b.x, y-b.y, z-b.z};
    }
    Point operator ^ (const Point &b) const {    //向量 a 与 b 的叉积 
        return Point{(y*b.z-z*b.y), (z*b.x-x*b.z), (x*b.y-y*b.x)};
    }
} p[4];
int dcmp(double x) {        // x为混合积,判正负,x==0表示4点共面 
    if(fabs(x)<eps) return 0;
    return x<0?-1:1;
}
double MixMul(Point a, Point b, Point c) {        //求向量a,b,c的混合积 
    return a.x*b.y*c.z+a.y*b.z*c.x+a.z*b.x*c.y-a.x*b.z*c.y-a.y*b.x*c.z-a.z*b.y*c.x;
}
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 Heron(double a, double b, double c) {    //海伦公式求三角形面积 
    double p=(a+b+c)/2;
    return sqrt(p*(p-a)*(p-b)*(p-c));
}
double getsqr(Point a, Point b, Point c) {        //通过海伦公式求三个向量构成的面的面积 
    return Heron(dis(a,b), dis(b,c), dis(a,c));
}

int main()
{
    while(~scanf("%lf %lf %lf", &p[0].x, &p[0].y, &p[0].z)) 
    {
        rep(i,1,3) scanf("%lf %lf %lf", &p[i].x, &p[i].y, &p[i].z);
        v=fabs(MixMul(p[0]-p[1], p[0]-p[2], p[0]-p[3]));
        if(dcmp(v)==0) {
            puts("O O O O");
            continue;
        }
        
        s[3]=getsqr(p[0], p[1], p[2]);        // 分别求出4个面的面积s[i]
        s[2]=getsqr(p[0], p[1], p[3]);
        s[1]=getsqr(p[0], p[2], p[3]);
        s[0]=getsqr(p[1], p[2], p[3]);
        sum=0;
        rep(i,0,3) s[i]=fabs(s[i]), sum+=s[i];    // sum为四个面的面积和,内切球半径 = v/2/sum 
        x=y=z=0;
        rep(i,0,3) {
            x+=p[i].x*s[i];
            y+=p[i].y*s[i];
            z+=p[i].z*s[i];
        }
        x/=sum, y/=sum, z/=sum;        //内切球球心坐标公式 
        printf("%.4f %.4f %.4f %.4f
", x, y, z, v/2/sum);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/sbfhy/p/6592014.html