hdu4266(三维凸包模板题)
/*给出三维空间中的n个顶点,求解由这n个顶点构成的凸包表面的多边形个数.
增量法求解:首先任选4个点形成的一个四面体,然后每次新加一个点,分两种情况:
1> 在凸包内,则可以跳过
2> 在凸包外,找到从这个点可以"看见"的面,删除这些面,
然后对于一边没有面的线段,和新加的这个点新建一个面,至于这个点可以看见的面,
就是求出这个面的方程(可以直接求法向量).
*/
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAXN=;
const double EPS=1e-;
struct Point
{
double x,y,z;
Point(){}
Point(double xx,double yy,double zz):x(xx),y(yy),z(zz){} Point operator -(const Point p1) //两向量之差
{
return Point(x-p1.x,y-p1.y,z-p1.z);
} Point operator *(Point p) //叉乘
{
return Point(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);
} double operator ^(Point p) //点乘
{
return (x*p.x+y*p.y+z*p.z);
}
void read()
{
scanf("%lf%lf%lf",&x,&y,&z);
}
};
struct CH3D
{
struct face
{
int a,b,c; //表示凸包一个面上三个点的编号
bool ok; //表示该面是否属于最终凸包中的面
}; int n; //初始顶点数
Point P[MAXN]; //初始顶点 int num; //凸包表面的三角形数
face F[*MAXN]; int g[MAXN][MAXN]; //凸包表面的三角形 double vlen(Point a) //向量长度
{
return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);
} Point cross(const Point &a, const Point &b, const Point &c) //叉乘
{
return Point((b.y-a.y)*(c.z-a.z)-(b.z-a.z)*(c.y-a.y),-((b.x-a.x)*(c.z-a.z)
-(b.z-a.z)*(c.x-a.x)),(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x));
}
double area(Point a,Point b,Point c) //三角形面积*2
{
return vlen((b-a)*(c-a));
} double volume(Point a,Point b,Point c,Point d) //四面体有向体积*6
{
return (b-a)*(c-a)^(d-a);
} double dblcmp(Point &p,face &f) //正:点在面同向
{
Point m=P[f.b]-P[f.a];
Point n=P[f.c]-P[f.a];
Point t=p-P[f.a];
return (m*n)^t;
} void deal(int p,int a,int b)
{
int f=g[a][b];
face add;
if(F[f].ok)
{
if(dblcmp(P[p],F[f])>EPS)
dfs(p,f);
else
{
add.a=b;
add.b=a;
add.c=p;
add.ok=;
g[p][b]=g[a][p]=g[b][a]=num;
F[num++]=add;
}
}
} void dfs(int p,int now)
{
F[now].ok=;
deal(p,F[now].b,F[now].a);
deal(p,F[now].c,F[now].b);
deal(p,F[now].a,F[now].c);
} bool same(int s,int t)
{
Point &a=P[F[s].a];
Point &b=P[F[s].b];
Point &c=P[F[s].c];
return fabs(volume(a,b,c,P[F[t].a]))<EPS && fabs(volume(a,b,c,P[F[t].b]))<EPS
&& fabs(volume(a,b,c,P[F[t].c]))<EPS;
} void solve() //构建三维凸包
{
int i,j,tmp;
face add;
bool flag=true;
num=;
if(n<)
return;
for(i=;i<n;i++) //此段是为了保证前四个点不共面,若以保证,则可去掉
{
if(vlen(P[]-P[i])>EPS)
{
swap(P[],P[i]);
flag=false;
break;
}
}
if(flag)
return;
flag=true;
for(i=;i<n;i++) //使前三点不共线
{
if(vlen((P[]-P[])*(P[]-P[i]))>EPS)
{
swap(P[],P[i]);
flag=false;
break;
}
}
if(flag)
return;
flag=true;
for(i=;i<n;i++) //使前四点不共面
{
if(fabs((P[]-P[])*(P[]-P[])^(P[]-P[i]))>EPS)
{
swap(P[],P[i]);
flag=false;
break;
}
}
if(flag)
return;
for(i=;i<;i++)
{
add.a=(i+)%;
add.b=(i+)%;
add.c=(i+)%;
add.ok=true;
if(dblcmp(P[i],add)>)
swap(add.b,add.c);
g[add.a][add.b]=g[add.b][add.c]=g[add.c][add.a]=num;
F[num++]=add;
}
for(i=;i<n;i++)
{
for(j=;j<num;j++)
{
if(F[j].ok && dblcmp(P[i],F[j])>EPS)
{
dfs(i,j);
break;
}
}
}
tmp=num;
for(i=num=;i<tmp;i++)
if(F[i].ok)
{
F[num++]=F[i];
}
} double area() //表面积
{
double res=0.0;
if(n==)
{
Point p=cross(P[],P[],P[]);
res=vlen(p)/2.0;
return res;
}
for(int i=;i<num;i++)
res+=area(P[F[i].a],P[F[i].b],P[F[i].c]);
return res/2.0;
} double volume() //体积
{
double res=0.0;
Point tmp(,,);
for(int i=;i<num;i++)
res+=volume(tmp,P[F[i].a],P[F[i].b],P[F[i].c]);
return fabs(res/6.0);
} int triangle() //表面三角形个数
{
return num;
} int polygon() //表面多边形个数
{
int i,j,res,flag;
for(i=res=;i<num;i++)
{
flag=;
for(j=;j<i;j++)
if(same(i,j))
{
flag=;
break;
}
res+=flag;
}
return res;
}
Point getcent()//求凸包质心
{
Point ans(,,),temp=P[F[].a];
double v = 0.0,t2;
for(int i=;i<num;i++){
if(F[i].ok == true){
Point p1=P[F[i].a],p2=P[F[i].b],p3=P[F[i].c];
t2 = volume(temp,p1,p2,p3)/6.0;//体积大于0,也就是说,点 temp 不在这个面上
if(t2>){
ans.x += (p1.x+p2.x+p3.x+temp.x)*t2;
ans.y += (p1.y+p2.y+p3.y+temp.y)*t2;
ans.z += (p1.z+p2.z+p3.z+temp.z)*t2;
v += t2;
}
}
}
ans.x /= (*v); ans.y /= (*v); ans.z /= (*v);
return ans;
}
double function(Point fuck){//点到凸包上的最近距离(枚举每个面到这个点的距离)
double min=;
for(int i=;i<num;i++){
if(F[i].ok==true){
Point p1=P[F[i].a] , p2=P[F[i].b] , p3=P[F[i].c];
double a = ( (p2.y-p1.y)*(p3.z-p1.z)-(p2.z-p1.z)*(p3.y-p1.y) );
double b = ( (p2.z-p1.z)*(p3.x-p1.x)-(p2.x-p1.x)*(p3.z-p1.z) );
double c = ( (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x) );
double d = ( -(a*p1.x+b*p1.y+c*p1.z) );
double temp = fabs(a*fuck.x+b*fuck.y+c*fuck.z+d)/sqrt(a*a+b*b+c*c);
if(temp<min)min = temp;
}
}
return min;
} }; int main()
{
int n;
while(scanf("%d",&n) && n)
{
CH3D hull;
hull.n=n;
for(int i=;i<n;i++)
{
hull.P[i].read();
}
hull.solve();
int q;
scanf("%d",&q);
for(int i=;i<q;i++)
{
Point tp;
tp.read();
double ans=1e9;
ans = min(ans, hull.function(tp) );
printf("%.4lf\n",ans);
}
}
return ;
}
求点到三维凸包的最小距离,直接用模板暴力枚举即可。
hdu4266(三维凸包模板题)的更多相关文章
- POJ3528 HDU3662 三维凸包模板
POJ3528 HDU3662 第一道题 给定若干点 求凸包的表面积,第二题 给定若干点就凸包的面数. 简单说一下三维凸包的求法,首先对于4个点假设不共面,确定了唯一四面体,对于一个新的点,若它不在四 ...
- POJ 3348 Cows | 凸包模板题
题目: 给几个点,用绳子圈出最大的面积养牛,输出最大面积/50 题解: Graham凸包算法的模板题 下面给出做法 1.选出x坐标最小(相同情况y最小)的点作为极点(显然他一定在凸包上) 2.其他点进 ...
- hdu 1348 Wall(凸包模板题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1348 Wall Time Limit: 2000/1000 MS (Java/Others) M ...
- POJ:Dungeon Master(三维bfs模板题)
Dungeon Master Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16748 Accepted: 6522 D ...
- HDU 1392 凸包模板题,求凸包周长
1.HDU 1392 Surround the Trees 2.题意:就是求凸包周长 3.总结:第一次做计算几何,没办法,还是看了大牛的博客 #include<iostream> #inc ...
- POJ 1113 凸包模板题
上模板. #include <cstdio> #include <cstring> #include <iostream> #include <algorit ...
- bzoj1670 Usaco2006 Building the Moat护城河的挖掘 [凸包模板题]
Description 为了防止口渴的食蚁兽进入他的农场,Farmer John决定在他的农场周围挖一条护城河.农场里一共有N(8<=N<=5,000)股泉水,并且,护城河总是笔直地连接在 ...
- UVA 11769 All Souls Night 的三维凸包要求的表面面积
主题链接:option=com_onlinejudge&Itemid=8&page=show_problem&problem=2869">点击打开链接 求给定的 ...
- hdu 1348 凸包模板
http://acm.hdu.edu.cn/showproblem.php?pid=1348 造城墙问题,求出凸包加上一圈圆的周长即可 凸包模板题 #include <cstdio> #i ...
随机推荐
- Unity Dynamic Batching
public class test1 : MonoBehaviour { public GameObject prefab; void Start() { ; i < ; i++) { Game ...
- mui.fire() 和 mui.trigger()
导读:添加自定义事件监听操作和标准js事件监听类似,可直接通过window对象添加,通过mui.fire()方法可触发目标窗口的自定义事件 监听自定义事件 添加自定义事件监听操作和标准js事件监听类似 ...
- AngularJs学习笔记(2)——ng-include
编写html文档的时候,为了实现代码模块化,增加复杂页面的代码可读性和可维护性,我们常常会想到将代码分散写入不同的HTML文件 angularJS里面的ng-include指令结合ng-control ...
- (016)给定一个有序数组(递增),敲代码构建一棵具有最小高度的二叉树(keep it up)
给定一个有序数组(递增),敲代码构建一棵具有最小高度的二叉树. 因为数组是递增有序的.每次都在中间创建结点,类似二分查找的方法来间最小树. struct TreeNode { int data; Tr ...
- 组播和广播的概念,IGMP的用途
1.组播和广播的概念 1) 组播 主机之间的通讯模式,也就是加入了同一个组的主机可以接收到此组内的所有数据,网络中的交换机和路由器只向有需求者复制并转发其所需数据. 主机可以向路由器请求加入或退出某个 ...
- mongo aggregate
https://cnodejs.org/topic/59264f62855efbac2cf7a2f3 背景 现有1000条学生记录,结构如下: { name:String,//名称 clazz:{ty ...
- Android JNI和NDK学习(03)--动态方式实现JNI(转)
本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092491.html 前面总结了静态实现JNI的方法,本文介绍如何动态实现J ...
- LNMP平滑升级nginx并安装ngx_lua模块教程
#ngx_lua module项目地址 https://github.com/chaoslawful/lua-nginx-module 在LNMP安装包后,重编译nginx,并添加ngx_lua模块 ...
- std::copy ( myvector.begin(), myvector.end(), out_it )
在实际生产环境中,不能进行调试,所以程序通常需要编译一个DEBUG版本来辅助我们找出问题所在,编译这样的DEBUG版本最常用的手段就是在关键处输出我们关心一些变量的值到屏幕. 如果输出的简单的变量值, ...
- html 常用
1. var canvas = document.getElementById("tutorial"); var ctx = canvas.getContext("2d& ...