zoukankan      html  css  js  c++  java
  • 【LOJ】#2070. 「SDOI2016」平凡的骰子

    题解

    用了一堆迷之复杂的结论结果迷之好写的计算几何????

    好吧,要写立体几何了

    如果有名词不懂自己搜吧

    首先我们求重心,我们可以求带权重心,也就是x坐标的话是所有分割的小四面体的x坐标 * 四面体体积的和除以骰子的体积,y,z坐标同理

    然后我们把这个骰子四面体剖分,剖分的话就是随便选在骰子内的一个点,对于骰子的每个面找相邻的三个点和这个点作为顶点组成的四面体

    四面体的重心是四个点三维坐标和除以4

    四面体的体积是三维混合积的绝对值除以6

    然后对于每个面,我们把它剖分成三角形,发现它们二面角的和就是左右相邻的两条边和重心组成的面二面角的和

    求出两个面二面角的法向量(就是垂直于平面的直线,可以用三维叉积求出来),然后求两个法向量的夹角,可以求出余弦值然后用反函数

    代码

    #include <bits/stdc++.h>
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mp make_pair
    #define MAXN 1000005
    #define mo 999999137
    #define pb push_back
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;T f = 1;char c = getchar();
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') {
            res = res * 10 + c - '0';
            c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    const db PI = acos(-1.0);
    struct Point {
        db x,y,z;
        Point(){}
        Point(db _x,db _y,db _z) {x = _x;y = _y;z = _z;}
        friend Point operator + (const Point &a,const Point &b) {return Point(a.x + b.x,a.y + b.y,a.z + b.z);}
        friend Point operator - (const Point &a,const Point &b) {return Point(a.x - b.x,a.y - b.y,a.z - b.z);}
        friend Point operator * (const Point &a,const db &d) {return Point(a.x * d,a.y * d,a.z * d);}
        friend Point operator / (const Point &a,const db &d) {return Point(a.x / d,a.y / d,a.z / d);}
        friend Point operator * (const Point &a,const Point &b) {return Point(a.y * b.z - a.z * b.y,-a.x * b.z + a.z * b.x,a.x * b.y - a.y * b.x);}
        friend db dot(const Point &a,const Point &b) {return a.x * b.x + a.y * b.y + a.z * b.z;}
        Point operator -= (const Point &b) {return *this = *this - b;}
        Point operator += (const Point &b) {return *this = *this + b;}
        Point operator /= (const db &d) {return *this = *this / d;}
        Point operator *= (const db &d) {return *this = *this * d;}
        db norm() {
            return sqrt(x * x + y * y + z * z);
        }
    }P[55],G;
    vector<Point> S[85];
    int N,F;
    Point GetG(Point p,Point a,Point b,Point c) {
        return (p + a + b + c) / 4.0;
    }
    db GetV(Point p,Point a,Point b,Point c) {
        a -= p;b -= p;c -= p;
        db res = abs(dot(a,b * c));
        res /= 6.0;
        return res;
    }
    Point CalcG() {
        Point t = Point(0.0,0.0,0.0);
        db sv = 0.0;
        for(int i = 1 ; i <= F ; ++i) {
            int s = S[i].size();
            for(int j = 0 ; j <= s - 1 ; ++j) {
                Point tmp = GetG(P[1],S[i][j],S[i][(j + 1) % s],S[i][(j + 2) % s]);
                db v = GetV(P[1],S[i][j],S[i][(j + 1) % s],S[i][(j + 2) % s]);
                sv += v;t += tmp * v;
            }
        }
        t /= sv;
        return t;
    }
    db CalcTangle(Point p,Point x,Point y,Point z) {
        x -= p;y -= p;z -= p;
        return acos(dot(x * y,x * z) / (x * y).norm() / (x * z).norm());
    }
    void Init() {
        read(N);read(F);
        db x,y,z;
        for(int i = 1 ; i <= N ; ++i) {
            scanf("%lf%lf%lf",&x,&y,&z);
            P[i] = Point(x,y,z);
        }
        int k,a;
        for(int i = 1 ; i <= F ; ++i) {
            read(k);
            for(int j = 1 ; j <= k ; ++j) {
                read(a);
                S[i].pb(P[a]);
            }
        }
    }
    void Solve() {
        Point G = CalcG();
        for(int i = 1 ; i <= F ; ++i) {
            int s = S[i].size();
            db x = -(s - 2) * PI;
            for(int j = 0 ; j < s ; ++j) {
                x += CalcTangle(G,S[i][j],S[i][(j + 1) % s],S[i][(j - 1 + s) % s]);
            }
            printf("%.7lf
    ",x / (4 * PI));
        }
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
    
  • 相关阅读:
    C#基础
    进制转换
    养猪和存储空间
    独热码和二进制码
    mux_xz
    饮料机
    亚稳态
    mos管功耗
    功能覆盖率和代码覆盖率
    时序逻辑电路输出特点
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9536511.html
Copyright © 2011-2022 走看看