Luogu P4080 [SDOI2016]平凡的骰子

Link
首先我们需要计算出该凸多面体的重心。
我们将其四面体剖分,设\(g_i,v_i\)分别为第\(i\)个四面体的重心和体积,那么整个凸多面体的重心就是\(\frac{\sum\limits a_iv_i}{\sum v_i}\)
我们知道一个凸四面体的重心就是四个顶点坐标的平均值,而一个凸四面体的体积可以利用混合积求出,这样我们就求出了该凸多面体的重心。
然后我们要求出该凸多面体每一个表面对应的单位球上的球面的面积。
我们将每个表面三角剖分,这样我们就只需要计算多个球面三角形的面积了。
题目中已经给出了计算球面三角形的公式,我们只需要计算二面角即可。
先利用叉积计算出法向量,然后利用点积计算出法向量之间的夹角,就可以得到二面角了。

#include<cmath>
#include<cstdio>
using db=double;
const int N=107;const db pi=acos(-1);
struct vec{db x,y,z;}a[N],h[N*N];
vec operator+(const vec&a,const vec&b){return {a.x+b.x,a.y+b.y,a.z+b.z};}
vec operator-(const vec&a,const vec&b){return {a.x-b.x,a.y-b.y,a.z-b.z};}
vec operator*(const vec&a,const vec&b){return {a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x};}
db operator^(const vec&a,const vec&b){return a.x*b.x+a.y*b.y+a.z*b.z;}
vec operator*(const vec&a,const db&b){return {a.x*b,a.y*b,a.z*b};}
db len(const vec&a){return sqrt(a^a);}
db cross(const vec&a,const vec&b,const vec&c){vec p=b*a,q=c*a;return acos((p^q)/len(p)/len(q));}
int n,m,f[N][N],d[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].z);
    for(int i=1,j;i<=m;++i) for(scanf("%d",d+i),j=1;j<=d[i];++j) scanf("%d",&f[i][j]);
    vec G=a[1],O={0,0,0},u,v,w,r;db s=0,t;
    for(int i=1;i<=m;++i)
    {
	u=a[f[i][1]];
	for(int j=2;j<d[i];++j) v=a[f[i][j]],w=a[f[i][j+1]],r=(G+u+v+w)*0.25,t=fabs((v-u)*(w-u)^(G-u)),O=O+r*t,s+=t;
    }
    G=O*(1/s),t=0.25/pi;
    for(int i=1;i<=n;++i) a[i]=a[i]-G;
    for(int i=1;i<=m;++i)
    {
        s=(2-d[i])*pi;
	for(int j=1;j<=d[i];++j) s+=cross(a[f[i][j]],a[f[i][j==1? d[i]:j-1]],a[f[i][j%d[i]+1]]);
        printf("%.7lf\n",s*t);
    }
}
posted @ 2020-02-24 10:02  Shiina_Mashiro  阅读(151)  评论(0编辑  收藏  举报