首页 > 代码库 > 2017-03-18 HDU 5733 计算几何 codeforces 599E 状压dp(待补)

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 0x3f3f3f3ftypedef 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\n", x, y, z, v/2/sum);    }    return 0;}

 

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