HDU 4273
计算凸包重心到各面的最短距离。
若知道重心,按四面体用体积法即可求出高。
关键在于,多面体重心的求法。这必须把多面体分割成多个四面体来求。下面从多边形的重心说起。
一般来用,对于一个多边形(p0,p1,p2....pn-1),其重心一般为pc.x=(p0.x+p1.x+....)/n对于y也一样。
但这其实是不正确的。反例以梯形为例。上面的式子当各点的权值均匀时是正确的。(三角形是一个特例)
但在多边形上,由于面的密度一样,所以,应当是与面积有关的。于是,把多边形分割成多个三角形,求出其重心。这样重心组成一个新的多边形与原多边形重心相同。于是,就把质量都集中在了重心上。而质量与面积相关。
于是,可由代码求重心:
以P0为顶点划分三角形,求得是有向面积,因为可以正负抵消 for(多边形上的点){ //逆时针
与p0组成三角形。
有向面积V=(p1-p0)*(p2-p0)/2;
Vtot+=V;
sum_x+=(p1.x+p2.x+p0.x)*V;
sum_y+=(p1.y+p2.y+p0.y)*V;
C.x=sum_x/3/Vtot; C.y=sum_y/3/Vtot
}
对于求多面体,只需划分成四面体来求即可。增加一个z坐标,同时
sum_x+=(p1.x+p2.x+p0.x+p3.x)*V;
C.x=sum_x/4/Vtot;
/*
增量法求凸包。选取一个四面体,同时把它各面的方向向量向外,增加一个点时,若该点与凸包上的某些面的方
向向量在同一侧,则去掉那些面,并使某些边与新增点一起连成新的凸包上的面。
*/ #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath> using namespace std;
const int MAXN=110;
const double eps=1e-8;
const double inf=1e10;
struct point {
double x,y,z;
};
struct face {
int a,b,c;
bool ok;
};
int n; //初始点数
point p[MAXN]; //空间点
int trianglecnt; //凸包上三角形数
face tri[6*MAXN]; //凸包上被创建的三角形
int vis[MAXN][MAXN]; //点i到点j是属于哪一个三角形。此处是有方向 point operator -(const point &x, const point &y){
point ret;
ret.x=x.x-y.x; ret.y=x.y-y.y; ret.z=x.z-y.z;
return ret;
} point operator * (const point &u,const point &v){ //叉积
point ret;
ret.x=u.y*v.z-u.z*v.y;
ret.y=u.z*v.x-u.x*v.z;
ret.z=u.x*v.y-u.y*v.x;
return ret;
} double operator ^(const point &u,const point &v){ //点积
return (u.x*v.x+u.y*v.y+u.z*v.z);
} double dist(point t){
return sqrt(t.x*t.x+t.y*t.y+t.z*t.z);
} double ptoplane(point &tmp,face &f){ //若结果大于0,证明点面的同向,即法向量方向
point m=p[f.b]-p[f.a]; point n=p[f.c]-p[f.a];
point t=tmp-p[f.a];
return (m*n)^t;
} double farea(point a,point b,point c ){
point t1=a-c; point t2=b-c;
return fabs(dist(t1*t2));
}
void dfs(int pt, int ct);
void deal(int pt,int a,int b){
int f=vis[a][b]; //所属三角形,即原来的ab。
face add;
if(tri[f].ok){
if((ptoplane(p[pt],tri[f]))>eps) dfs(pt,f); //若点同样在该f三角形方向一侧,继续调整
else {
add.a=b; add.b=a; add.c=pt; add.ok=1;
vis[pt][b]=vis[a][pt]=vis[b][a]=trianglecnt;
tri[trianglecnt++]=add;
}
}
} void dfs(int pt, int ct){
tri[ct].ok=0; //去掉该面
deal(pt,tri[ct].b,tri[ct].a); //因为有向边ab所属三角形去掉,则反方向边必定属于另一个三角形.
deal(pt,tri[ct].c,tri[ct].b);
deal(pt,tri[ct].a,tri[ct].c);
} void construct (){
int i,j;
trianglecnt=0;
if(n<4) return ; //不可能构成一个多面体
bool tmp=true;
for(i=1;i<n;i++){ //不共点两点
if(dist(p[0]-p[i])>eps){
swap(p[1],p[i]); tmp=false; break;
}
}
if(tmp) return ;
tmp=true;
for(i=2;i<n;i++){ //不共线
if(dist((p[0]-p[1])*(p[1]-p[i]))>eps){
swap(p[2],p[i]); tmp=false; break;
}
}
if(tmp) return ;
tmp=true;
for(i=3;i<n;i++){ //四点不共面K
if(fabs((p[0]-p[1])*(p[1]-p[2])^(p[0]-p[i]))>eps){
swap(p[3],p[i]); tmp=false; break;
}
}
if(tmp) return ;
face add;
for(i=0;i<4;i++){ //使各三角形的方向向量向外,同时记录下三角形的序号
add.a=(i+1)%4; add.b=(i+2)%4; add.c=(i+3)%4; add.ok=1; //等于1表示在凸包上
if(ptoplane(p[i],add)>0) swap(add.b,add.c);
vis[add.a][add.b]=vis[add.b][add.c]=vis[add.c][add.a]=trianglecnt;
tri[trianglecnt++]=add;
}
for(i=4;i<n;i++){ //构建凸包
for(j=0;j<trianglecnt;j++){
if(tri[j].ok&&(ptoplane(p[i],tri[j]))>eps){ //增加点可见该平,即在面方向一侧
dfs(i,j); break;
}
}
}
int cnt=trianglecnt;
trianglecnt=0;
for(i=0;i<cnt;i++){ //只有ok为1的才属于凸包上的三角形
if(tri[i].ok){
tri[trianglecnt++]=tri[i];
}
}
} double cdis(point p0){
double ans=inf;
point p1,p2,p3;
for(int i=0;i<trianglecnt;i++){
p1=p[tri[i].a]; p2=p[tri[i].b];
p3=p[tri[i].c];
double V=fabs(((p0-p1)^((p2-p1)*(p3-p1)))/6);
// printf("%lf\n",V);
ans=min(ans,V*3*2/dist((p2-p1)*(p3-p1)));
}
return ans; } point Cenconstruct(){
point p0=p[0];
point p1,p2,p3; double sum_area=0,sum_x=0,sum_y=0,sum_z=0;
for(int i=0;i<trianglecnt;i++){
p1=p[tri[i].a]; p2=p[tri[i].b]; p3=p[tri[i].c];
double V=((p0-p1)^((p2-p1)*(p3-p1)))/6;
sum_area+=V;
sum_x+=(p0.x+p1.x+p2.x+p3.x)*V;
sum_y+=(p0.y+p1.y+p2.y+p3.y)*V;
sum_z+=(p0.z+p1.z+p2.z+p3.z)*V;
}
point ret;
ret.x=sum_x/4/sum_area; ret.y=sum_y/4/sum_area; ret.z=sum_z/4/sum_area;
return ret;
}
int main(){
while(scanf("%d",&n)!=EOF){
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
construct();
point centroid=Cenconstruct();
double ans;
ans = cdis(centroid);
printf("%.3lf\n",ans);
}
}
HDU 4273的更多相关文章
- hdu 4273 2012长春赛区网络赛 三维凸包中心到最近面距离 ***
新模板 /* HDU 4273 Rescue 给一个三维凸包,求重心到表面的最短距离 模板题:三维凸包+多边形重心+点面距离 */ #include<stdio.h> #include&l ...
- 2012年长春网络赛(hdu命题)
为迎接9月14号hdu命题的长春网络赛 ACM弱校的弱菜,苦逼的在机房(感谢有你)呻吟几声: 1.对于本次网络赛,本校一共6名正式队员,训练靠的是完全的自主学习意识 2.对于网络赛的群殴模式,想竞争现 ...
- HDOJ 2111. Saving HDU 贪心 结构体排序
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 【HDU 3037】Saving Beans Lucas定理模板
http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...
- hdu 4859 海岸线 Bestcoder Round 1
http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...
- HDU 4569 Special equations(取模)
Special equations Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u S ...
- HDU 4006The kth great number(K大数 +小顶堆)
The kth great number Time Limit:1000MS Memory Limit:65768KB 64bit IO Format:%I64d & %I64 ...
- HDU 1796How many integers can you find(容斥原理)
How many integers can you find Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d ...
- hdu 4481 Time travel(高斯求期望)(转)
(转)http://blog.csdn.net/u013081425/article/details/39240021 http://acm.hdu.edu.cn/showproblem.php?pi ...
随机推荐
- 3.4 存储简单数据的利器——Preferences
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="ht ...
- js点击特效
//点击效果博客页面点击就可以看到 <script type="text/javascript"> !function(e, t, a) { function n() ...
- this引用逃逸问题
//this引用逃逸 // 1.构造器还未完成前,将自身this引用向外抛,使其他线程访问这个引用,进而访问到其未初始化的变量,造成问题 // 2.内部类访问外部类未初始化的成员变量 //3.多态继承 ...
- [BZOJ1821][JSOI2010]部落划分
感觉学了这么久还是有那么一丢丢进步的...上个学期看到这道题,虽然早就学过并查集和二分了但还是一点思路都没有,现在可以秒切了呢 思路就是二分+并查集,有些人说是生成树,其实它没有变成树,只是运用了生成 ...
- Ubuntu1804安装Postgresql【转】
转载自:https://huur.cn/course/yw/1591.html 关系数据库管理系统是许多网站和应用程序的关键组成部分.它们提供了一种结构化的方式来存储,组织和访问信息. Postgre ...
- Windows 环境下 Docker 使用及配置
原文引用: https://www.cnblogs.com/moashen/p/8067612.html 我们可以使用以下两种方式在Windows环境下使用docker: 1. 直接安装: Docke ...
- WebApi里面路由机制的原理以及路由匹配的过程
1.WebApi服务启动之后,会执行全局配置文件Global.asax.cs的 protected void Application_Start(){GlobalConfiguration.Confi ...
- HTTPS 为什么更安全,先看这些
HTTPS 是建立在密码学基础之上的一种安全通信协议,严格来说是基于 HTTP 协议和 SSL/TLS 的组合.理解 HTTPS 之前有必要弄清楚一些密码学的相关基础概念,比如:明文.密文.密码.密钥 ...
- angular js 球星
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- Sql语句优化-查询两表不同行NOT IN、NOT EXISTS、连接查询Left Join
在实际开发中,我们往往需要比较两个或多个表数据的差别,比较那些数据相同那些数据不相同,这时我们有一下三种方法可以使用:1. IN或NOT IN,2. EXIST或NOTEXIST,3.使用连接查询(i ...