HDU 3662

求的是凸包有多少个面。

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

/*
增量法求凸包。选取一个四面体,同时把它各面的方向向量向外,增加一个点时,若该点与凸包上的某些面的方
向向量在同一侧,则去掉那些面,并使某些边与新增点一起连成新的凸包上的面。
*/

#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

时间: 2024-10-29 00:20:24

HDU 3662的相关文章

POJ 3528 hdu 3662 三维凸包模板题

POJ 3528题:http://poj.org/problem?id=3528 HDU 3662:http://acm.hdu.edu.cn/showproblem.php?pid=3662 一个是求三维凸包面数,一个是求三维凸包表面积,都是很裸的. 贴代码: #include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<stdlib.h>

Hdu 3662 3D Convex Hull(三维凸包)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3662 思路:三维凸包模板. #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define PR 1e-8 #define N 510 using namespace std; struct TPoint { doub

训练日志

计算几何学习进入了一个瓶颈啊 = = 有些偏难的东西进展很缓慢 加上最近做题类型确实单一 导致比赛的时候经常写跪 所以打算慢慢进展计算几何内容 每天都做一些常规的水题 先说下计算几何的情况 进入了扫描线部分 和之前普通的矩形周长并啥的画风完全不同了 目前搞出来的东西也挺少 HDU 3124 给你一些平面上不相交的圆 圆上的点的最近距离 平面最近点对有固定套路 但是放到圆上还有半径 不能套用(但据说现场有人考最近点对的做法搞过去了?) 求最近距离 考虑二分 剩下的就是快速判断圆是否相交 我们考虑扫

图论 500题——主要为hdu/poj/zoj

转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并查集======================================[HDU]1213   How Many Tables   基础并查集★1272   小希的迷宫   基础并查集★1325&&poj1308  Is It A Tree?   基础并查集★1856   More i

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1284 递推公式:dp[i] = sum(dp[i], dp[i-C]) /* 钱币兑换问题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6325 Accepted Submission(s): 3662 Problem Description

hdu图论题目分类

=============================以下是最小生成树+并查集====================================== [HDU] 1213 How Many Tables 基础并查集★ 1272 小希的迷宫 基础并查集★ 1325&&poj1308 Is It A Tree? 基础并查集★ 1856 More is better 基础并查集★ 1102 Constructing Roads 基础最小生成树★ 1232 畅通工程 基础并查集★ 123

HDU 1395 2^x mod n = 1

/* 中文题意: 中文翻译: 题目大意:求出最小的 n 使得2的 I 次方对 n 的值为1. 解题思路:如下: 难点详解:先用费马小定理了解2的 i 次方对偶数取余都不可能是一,还有就是排除 1 .之后要用中国剩余定理让 t 的值不超出 int 范围.不用这个定理我错了n次,都是超时.我猜测可能是 t 的值超出了int 的范围了,之后的数都是随机的,所以一直运行不出来,才会超时的.(不知道我的猜测对不对,欢迎大家指正) 关键点:理解费马小定理(我到现在还是不理解),只是用到了一点点这个东西.还有

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include