求的是凸包有多少个面。

注意,求的是面。这就需要把同一个面的三角形合并。只需判断两个三角形的法向量是否同向平行。

/*
增量法求凸包。选取一个四面体,同时把它各面的方向向量向外,增加一个点时,若该点与凸包上的某些面的方
向向量在同一侧,则去掉那些面,并使某些边与新增点一起连成新的凸包上的面。
*/ #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath> using namespace std;
const int MAXN=350;
const double eps=1e-8;
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是属于哪一个三角形。此处是有方向
bool vit[MAXN*6]; 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];
}
}
} void clean(){
memset(vit,false,sizeof(vit));
int counted=0;
for(int i=0;i<trianglecnt;i++){
if(vit[i]) continue;
vit[i]=true;
point vect1=(p[tri[i].b]-p[tri[i].a])*(p[tri[i].c]-p[tri[i].a]);
counted++;
for(int j=i+1;j<trianglecnt;j++){
point vect2=(p[tri[j].b]-p[tri[j].a])*(p[tri[j].c]-p[tri[j].a]);
if(dist(vect1*vect2)<eps&&(vect1^vect2)>0)
vit[j]=true;
}
}
printf("%d\n",counted);
} int main(){
while(scanf("%d",&n)!=EOF){
memset(vis,-1,sizeof(vis));
for(int i=0;i<n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
construct();
clean();
}
}

  

HDU 3662的更多相关文章

  1. 【HDU 3662】3D Convex Hull

    http://acm.hdu.edu.cn/showproblem.php?pid=3662 求给定空间中的点的三维凸包上有多少个面. 用增量法,不断加入点,把新加的点能看到的面都删掉,不能看到的面与 ...

  2. hdu 3662 3D Convex Hull

    Problem - 3662 题意很简单,构造三维凸包,求凸包有多少个面. 代码如下: #include <cstdio> #include <iostream> #inclu ...

  3. hdu 1284 钱币兑换问题 完全背包

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1284 递推公式:dp[i] = sum(dp[i], dp[i-C]) /* 钱币兑换问题 Time ...

  4. 【转载】图论 500题——主要为hdu/poj/zoj

    转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...

  5. HDU 5643 King's Game 打表

    King's Game 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5643 Description In order to remember hi ...

  6. hdu图论题目分类

    =============================以下是最小生成树+并查集====================================== [HDU] 1213 How Many ...

  7. poj和hdu部分基础算法分类及难度排序

    最近想从头开始刷点基础些的题,正好有个网站有关于各大oj的题目分类(http://www.pythontip.com/acm/problemCategory),所以写了点脚本把hdu和poj的一些题目 ...

  8. HDU图论题单

    =============================以下是最小生成树+并查集====================================== [HDU] 1213 How Many ...

  9. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

随机推荐

  1. javascript--给你的JS代码添加单元测试

    通过测试框架为JavaScript应用添加测试,从而保证代码的高质量.这里的笔记例子应用在jaywcjlove/validator.js中. 安装 用到三个工具chai(断言工具),mocha(测试框 ...

  2. tp的redis驱动

    1.增加分布式支持 使用方法:将文件存放在ThinkPHP框架根目录下的Library\Think\Session\Driver\目录下 config配置参数: //Redis Session配置 ' ...

  3. MySql c#通用类 转

    using System;using System.Data;using System.Configuration;using System.Collections.Generic;using Sys ...

  4. xhtml1-strict.dtd

    <!-- Extensible HTML version 1.0 Strict DTD This is the same as HTML 4 Strict except for changes ...

  5. 最近积累的JS 东西,分享一下

    js 关闭页面 var browserName=navigator.appName; if (browserName=="Netscape") { window.open('',' ...

  6. JS排序之选择排序

    遍历这个数组,先确定索引为0的数字为暂时最小数, 在剩下的数据中,以第一个为标杆,和剩下的数依次进行比较,如果标杆大于某数,则进行索引交换,继续比较,则a[i]=min; 最后让a[i]与索引为0的数 ...

  7. Android 解析JSON

    上次讲了XML格式数据的解析方式,这次要说的是如何解析JSON数据格式,相对与XML,JSON解析数据的方式在于它的体积更小,在网络上传输可以更省流量. 这次在网上找到一个中国天气json数据的API ...

  8. js邮箱正则表达式的使用

    在网页中插入邮箱输入框,当邮箱输入格式错误,给出提示.代码:function yy(){ var t = /^[A-Za-zd0-9]+([-_.][A-Za-zd]+)*@([A-Za-zd]+[- ...

  9. java中负数的补码转换为十进制

    一个数如果为正,则它的原码.反码.补码相同:一个正数的补码,将其转化为十进制,可以直接转换. 已知一个负数的补码,将其转换为十进制数,步骤: 1.先对各位取反: 2.将其转换为十进制数: 3.加上负号 ...

  10. (转)基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

    http://www.cnblogs.com/wuhuacong/p/3872890.html 我们在使用EasyUI的时候,很多情况下需要使用到表格控件datagrid,这个控件控件非常强大,使用起 ...