博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LOJ#2070. 「SDOI2016」平凡的骰子(计算几何)
阅读量:5752 次
发布时间:2019-06-18

本文共 3227 字,大约阅读时间需要 10 分钟。

题面

做一道题学一堆东西不管什么时候都是美好的体验呢……

前置芝士

混合积

对于三个三维向量\(a,b,c\),定义它们的混合积为\((a\times b)\cdot c\),其中$\times \(表示叉乘,\)\cdot\(表示点乘,记为\)[a b c]$

关于它的几何意义的话……图片来自网络

5cb0716e70817.png

其中\(Prj_{a\times b}c\)代表的是\(c\)这个向量在\(a\times b\)这个向量上的投影

那么显然我们最后得到的是以这三个向量为三条临边的一个六面体的体积

5cb071dbb2c80.png

四面体体积

假设四面体的四个顶点分别为\(A,B,C,D\),并设三个向量\(a=B-A,b=C-A,c=D-A\),那么这个正四面体的体积就是\({1\over 6}[a\ b\ c]\)

这个应该比较显然吧……看上面那幅图,四面体的体积是以\(ab\)这个平行四边形为底,\(c\)为顶点的棱锥的一半,而棱锥的体积是棱柱的\({1\over 3}\),所以四面体体积就是六面体的\({1\over 6}\)

凸多面体的重心

我们先来考虑一下凸多边形的重心好了……

对于三角形,它的重心就是它所有坐标的平均值

那么对于凸多边形,我们把它三角剖分了,记第\(i\)块的重心为\(a_i\),面积为\(m_i\),那么凸多边形的重心就是

\[{\sum_{i=1}^na_i\times m_i\over \sum_{i=1}^nm_i}\]

那么凸多面体也差不多了,我们把它给四面体剖分了,然后也差不多按上面的算就好了

关于四面体剖分,具体的说我们在多面体中随便选一个点,比方说是\(p_1\),然后把每一个面给三角剖分,那么三角形就和选定的点构成了一个四面体。设\(v_i\)表示第\(i\)个四面体的体积,\(a_i\)表示重心,则最终多面体的重心为

\[{\sum_{i=1}^na_i\times v_i\over \sum_{i=1}^nv_i}\]

二面角

这玩意儿班里数学课正在上然而我正在停课

简单来说就是两个平面的夹角

我们假设现在有\(a,b,c\)三个向量,要求\(ab\)这个平面和\(ac\)这个平面的二面角

那么求出\(ab\)\(ac\)的法向量(法向量可以直接用叉积算),两个法向量之间的夹角就是二面角了,法向量之间的夹角直接用点积除以长度计算

可以画个图来理解。我们俯视的话,即要求二面角\(\angle 1\),那么显然两个法向量的夹角\(\angle 2=\angle 1\)

5cb0773f7d5e4.png

题解

总结起来的话……

三维计算几何。

需要混合积求四面体体积;

四面体剖分后合并带权重心求总重心;

四面体重心的横纵坐标是四个顶点的横纵坐标的平均数;

三维差积求平面的法向量;

点积求法向量夹角(二面角)

这些知识就可以了AC此题了。

时间复杂度\(O(nf)\)

顺便说一下数据范围是\(n,f\leq 100\),题面里错了

//minamoto#include
#define R register#define inline __inline__ __attribute__((always_inline))#define fp(i,a,b) for(R int i=(a),I=(b)+1;i
I;--i)#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)using namespace std;const int N=105;const double Pi=acos(-1.0);struct node{ double x,y,z; inline node(){} inline node(R double xx,R double yy,R double zz):x(xx),y(yy),z(zz){} inline node operator +(const node &b)const{return node(x+b.x,y+b.y,z+b.z);} inline node operator -(const node &b)const{return node(x-b.x,y-b.y,z-b.z);} inline node operator *(const node &b)const{return node(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);} inline double operator ^(const node &b)const{return x*b.x+y*b.y+z*b.z;} inline node operator *(const double &b)const{return node(x*b,y*b,z*b);} inline node operator /(const double &b)const{return node(x/b,y/b,z/b);} inline double norm(){return sqrt(x*x+y*y+z*z);}}p[N],h[N*N],u,v;int f[N][N],c[N];double sum,tmp;int n,m;inline double cross(const node &a,const node &b,const node &c){ node p=b*a,q=c*a;return acos((p^q)/p.norm()/q.norm());}int main(){// freopen("testdata.in","r",stdin); scanf("%d%d",&n,&m); fp(i,1,n)scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z); fp(i,1,m){ scanf("%d",&c[i]); fp(j,1,c[i])scanf("%d",&f[i][j]); } u=p[1],v=node(0,0,0),sum=0; fp(i,1,m){ node u2=p[f[i][1]],v1,v2,t; fp(j,2,c[i]-1){ v1=p[f[i][j]],v2=p[f[i][j+1]]; t=(u+u2+v1+v2)*0.25,tmp=fabs(((v1-u2)*(v2-u2))^(u-u2)); v=v+t*tmp,sum+=tmp; } } tmp=1.0/sum,u=v*tmp,tmp=0.25/Pi; fp(i,1,n)p[i]=p[i]-u; fp(i,1,m){ sum=0; fp(j,2,c[i]-1)sum+=cross(p[f[i][j]],p[f[i][j-1]],p[f[i][j+1]]); sum+=cross(p[f[i][1]],p[f[i][c[i]]],p[f[i][2]]), sum+=cross(p[f[i][c[i]]],p[f[i][c[i]-1]],p[f[i][1]]); sum-=(c[i]-2)*Pi; printf("%.7lf\n",sum*tmp); } return 0;}

转载于:https://www.cnblogs.com/bztMinamoto/p/10698041.html

你可能感兴趣的文章
java.lang.UnsatisfiedLinkError:no dll in java.library.path终极解决之道
查看>>
我的工具:文本转音频文件
查看>>
【许晓笛】从零开始运行EOS系统
查看>>
【跃迁之路】【460天】程序员高效学习方法论探索系列(实验阶段217-2018.05.11)...
查看>>
C++入门读物推荐
查看>>
TiDB 源码阅读系列文章(七)基于规则的优化
查看>>
Spring之旅第八站:Spring MVC Spittr舞台的搭建、基本的控制器、请求的输入、表单验证、测试(重点)...
查看>>
数据结构与算法——常用排序算法及其Java实现
查看>>
你所不知的Webpack-多种配置方法
查看>>
webpack+typescript+threejs+vscode开发
查看>>
python读excel写入mysql小工具
查看>>
如何学习区块链
查看>>
搜索问题的办法
查看>>
微信分销系统商城营销5大重点
查看>>
求职准备 - 收藏集 - 掘金
查看>>
Linux-Centos启动流程
查看>>
php 设计模式
查看>>
后端技术精选 - 收藏集 - 掘金
查看>>
Laravel 服务容器
查看>>
mac安装kubernetes并运行echoserver
查看>>