题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3662
题目意思:给出n 个三维的点,求这些点组成的凸包的面数
//============================================================================
// Name : hdu3662.cpp
// Author : ssslpk
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
using namespace std;
#define X 0
#define Y 1
#define Z 2
#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))<eps)
typedef struct Vertex *tVertex;
typedef struct Edge *tEdge;
typedef struct Face *tFace;
struct point3{double x,y,z;};
struct Vertex {
double v[3];
int vnum;
bool onhull, processed;
tEdge duplicate; /* pointer to incident cone edge (or NULL) */
tVertex next, prev;
};
struct Edge {
tFace adjface[2];
tVertex endpts[2];
tFace newface; /* pointer to incident cone face. */
bool remove; /* T iff edge should be remove. */
tEdge next, prev;
};
struct Face {
tEdge edge[3];
tVertex vertex[3];
bool visible; /* T iff face visible from new point. */
tFace next, prev;
};
tVertex vertices = NULL;
tEdge edges = NULL;
tFace faces = NULL;
#define ADD(head, p) if (head) {\
p->next = head;\
p->prev = head->prev;\
head->prev = p;\
p->prev->next = p;\
}\
else {\
head = p;\
head->next = head->prev = p;\
}
#define DELETE(head, p) if (head) {\
if (head == head->next)\
head = NULL;\
else if (p == head)\
head = head->next;\
p->next->prev = p->prev;\
p->prev->next = p->next;\
delete (p);\
}
const double EPS = 1e-10;
int sgn(double d) {
return d < -EPS ? -1 : d > EPS;
}
//ŒÆËãcross product U x V
point3 xmult(point3 u,point3 v){
point3 ret;
ret.x=u.y*v.z-v.y*u.z;
ret.y=u.z*v.x-u.x*v.z;
ret.z=u.x*v.y-u.y*v.x;
return ret;
}
//ŒÆËãdot product U . V
double dmult(point3 u,point3 v){
return u.x*v.x+u.y*v.y+u.z*v.z;
}
//ÊžÁ¿²î U - V
point3 subt(point3 u,point3 v){
point3 ret;
ret.x=u.x-v.x;
ret.y=u.y-v.y;
ret.z=u.z-v.z;
return ret;
}
//È¡ÆœÃæ·šÏòÁ¿
point3 pvec(point3 s1,point3 s2,point3 s3){
return xmult(subt(s1,s2),subt(s2,s3));
}
//ÏòÁ¿ŽóС
double vlen(point3 p){
return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
}
tVertex MakeNullVertex(void) {
tVertex v = new Vertex;
v->duplicate = NULL;
v->onhull = false;
v->processed = false;
ADD(vertices, v);
return v;
}
tEdge MakeNullEdge(void) {
tEdge e = new Edge;
e->adjface[0] = e->adjface[1] = e->newface = NULL;
e->endpts[0] = e->endpts[1] = NULL;
e->remove = false;
ADD(edges, e);
return e;
}
tFace MakeNullFace(void) {
tFace f = new Face;
for (int i = 0; i < 3; ++i) {
f->edge[i] = NULL;
f->vertex[i] = NULL;
}
f->visible = false;
ADD(faces, f);
return f;
}
tFace MakeFace(tVertex v0, tVertex v1, tVertex v2, tFace fold) {
tEdge e0, e1, e2;
if (!fold) {
e0 = MakeNullEdge();
e1 = MakeNullEdge();
e2 = MakeNullEdge();
}
else {
e0 = fold->edge[2];
e1 = fold->edge[1];
e2 = fold->edge[0];
}
e0->endpts[0] = v0; e0->endpts[1] = v1;
e1->endpts[0] = v1; e1->endpts[1] = v2;
e2->endpts[0] = v2; e2->endpts[1] = v0;
tFace f = MakeNullFace();
f->edge[0] = e0; f->edge[1] = e1; f->edge[2] = e2;
f->vertex[0] = v0; f->vertex[1] = v1; f->vertex[2] = v2;
e0->adjface[0] = e1->adjface[0] = e2->adjface[0] = f;
return f;
}
void CleanEdges(void) {
tEdge e = edges;
do {
if (e->newface) {
if (e->adjface[0]->visible)
e->adjface[0] = e->newface;
else e->adjface[1] = e->newface;
e->newface = NULL;
}
e = e->next;
} while (e != edges);
while (edges && edges->remove) {
e = edges;
DELETE(edges, e);
}
e = edges->next;
do {
if (e->remove) {
tEdge t = e;
e = e->next;
DELETE(edges, t);
}
else e = e->next;
} while (e != edges);
}
void CleanFaces(void) {
tFace f;
while (faces && faces->visible) {
f = faces;
DELETE(faces, f);
}
f = faces->next;
do {
if (f->visible) {
tFace t = f;
f = f->next;
DELETE(faces, t);
}
else f = f->next;
} while (f != faces);
}
void CleanVertices(tVertex *pvnext) {
tVertex v, t;
tEdge e = edges;
do {
e->endpts[0]->onhull = e->endpts[1]->onhull = true;
e = e->next;
} while (e != edges);
while (vertices && vertices->processed && !vertices->onhull) {
if (v == *pvnext)
*pvnext = v->next;
v = vertices;
DELETE(vertices, v);
}
v = vertices->next;
do {
if (v->processed && !v->onhull) {
t = v;
v = v->next;
DELETE(vertices, t)
}
else v = v->next;
} while (v != vertices);
v = vertices;
do {
v->duplicate = NULL;
v->onhull = false;
v = v->next;
} while (v != vertices);
}
void CleanUp(tVertex *pvnext) {
CleanEdges();
CleanFaces();
CleanVertices(pvnext);
}
void SubVec(double a[3], double b[3], double c[3]) {
for (int i = 0; i < 2; ++i) c[i] = a[i] - b[i];
}
bool Collinear(tVertex a, tVertex b, tVertex c) {
double c0 = (c->v[Z] - a->v[Z]) * (b->v[Y] - a->v[Y]) - (b->v[Z] - a->v[Z]) * (c->v[Y] - a->v[Y]);
double c1 = (b->v[Z] - a->v[Z]) * (c->v[X] - a->v[X]) - (b->v[X] - a->v[X]) * (c->v[Z] - a->v[Z]);
double c2 = (b->v[X] - a->v[X]) * (c->v[Y] - a->v[Y]) - (b->v[Y] - a->v[Y]) * (c->v[X] - a->v[X]);
return c0 == 0 && c1 == 0 && c2 == 0;
}
double Volume(tFace f, tVertex p) {
double ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz;
ax = f->vertex[0]->v[X] - p->v[X];
ay = f->vertex[0]->v[Y] - p->v[Y];
az = f->vertex[0]->v[Z] - p->v[Z];
bx = f->vertex[1]->v[X] - p->v[X];
by = f->vertex[1]->v[Y] - p->v[Y];
bz = f->vertex[1]->v[Z] - p->v[Z];
cx = f->vertex[2]->v[X] - p->v[X];
cy = f->vertex[2]->v[Y] - p->v[Y];
cz = f->vertex[2]->v[Z] - p->v[Z];
double vol = (ax * (by * cz - bz * cy) + ay * (bz * cx - bx * cz) + az * (bx * cy - by * cx));
return vol;
}
void DoubleTriangle(void) {
tVertex v0, v1, v2, v3, t;
tFace f0, f1 = NULL;
tEdge e0, e1, e2, s;
v0 = vertices;
while (Collinear(v0, v0->next, v0->next->next))
if ((v0 = v0->next) == vertices)
printf("DoubleTriangle: All points are Collinear!\n"), exit(0);
v1 = v0->next;
v2 = v1->next;
v0->processed = true;
v1->processed = true;
v2->processed = true;
f0 = MakeFace(v0, v1, v2, f1);
f1 = MakeFace(v2, v1, v0, f0);
f0->edge[0]->adjface[1] = f1;
f0->edge[1]->adjface[1] = f1;
f0->edge[2]->adjface[1] = f1;
f1->edge[0]->adjface[1] = f0;
f1->edge[1]->adjface[1] = f0;
f1->edge[2]->adjface[1] = f0;
v3 = v2->next;
int vol = sgn(Volume(f0, v3));
while (!vol) {
if ((v3 = v3->next) == v0)
printf("DoubleTriangle: All points are coplanar!\n"), exit(0);
vol = sgn(Volume(f0, v3));
}
vertices = v3;
}
void MakeCcw(tFace f, tEdge e, tVertex p) {
tFace fv;
if (e->adjface[0]->visible) fv = e->adjface[0];
else fv = e->adjface[1];
int i;
for (i = 0; fv->vertex[i] != e->endpts[0]; ++i)
;
if (fv->vertex[(i + 1) % 3] != e->endpts[1]) {
f->vertex[0] = e->endpts[1];
f->vertex[1] = e->endpts[0];
}
else {
f->vertex[0] = e->endpts[0];
f->vertex[1] = e->endpts[1];
swap(f->edge[1], f->edge[2]);
}
f->vertex[2] = p;
}
tFace MakeConeFace(tEdge e, tVertex p) {
tEdge new_edge[2];
for (int i = 0; i < 2; ++i)
if (!(new_edge[i] = e->endpts[i]->duplicate)) {
new_edge[i] = MakeNullEdge();
new_edge[i]->endpts[0] = e->endpts[i];
new_edge[i]->endpts[1] = p;
e->endpts[i]->duplicate = new_edge[i];
}
tFace new_face = MakeNullFace();
new_face->edge[0] = e;
new_face->edge[1] = new_edge[0];
new_face->edge[2] = new_edge[1];
MakeCcw(new_face, e, p);
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
if (!new_edge[i]->adjface[j]) {
new_edge[i]->adjface[j] = new_face;
break;
}
return new_face;
}
bool AddOne(tVertex p) {
bool visable = false;
tFace f = faces;
do {
int vol = sgn(Volume(f, p));
if (vol < 0) {
f->visible = true;
visable = true;
}
f = f->next;
} while (f != faces);
if (!visable) {
p->onhull = false;
return false;
}
tEdge e = edges;
do {
tEdge temp = e->next;
if (e->adjface[0]->visible && e->adjface[1]->visible)
e->remove = true;
else if (e->adjface[0]->visible || e->adjface[1]->visible)
e->newface = MakeConeFace(e, p);
e = temp;
} while (e != edges);
return true;
}
void ConstructHull(void) {
tVertex v = vertices;
tVertex vnext;
do {
vnext = v->next;
if (!v->processed) {
v->processed = true;
AddOne(v);
CleanUp(&vnext);
}
v = vnext;
} while (v != vertices);
}
double sqr(double x) {
return x * x;
}
double dist(Vertex a, Vertex b) {
return sqrt(sqr(a.v[X] - b.v[X]) + sqr(a.v[Y] - b.v[Y]) + sqr(a.v[Z] - b.v[Z]));
}
void Solve() {
DoubleTriangle();
ConstructHull();
}
int dots_onplane(point3 a,point3 b,point3 c,point3 d){
return zero(dmult(pvec(a,b,c),subt(d,a)));
}
int parallel(point3 u1,point3 u2,point3 u3,point3 v1,point3 v2,point3 v3){
return vlen(xmult(pvec(u1,u2,u3),pvec(v1,v2,v3)))<eps;
}
point3 vchangetop(Vertex p){
point3 v;
v.x = p.v[X]; v.y = p.v[Y]; v.z = p.v[Z];
return v;
}
void printout(point3 p){
printf("%lf %lf %lf\n",p.x,p.y,p.z);
}
int FaceArea(void) {
int ans = 0;
bool same;
tFace ff,f = faces;
do {
point3 p0 = vchangetop(*(f->vertex[0])), p1 = vchangetop(*(f->vertex[1])), p2 = vchangetop(*(f->vertex[2]));
ff = faces;
same = false;
while (ff!=f){
point3 v0 = vchangetop(*(ff->vertex[0])), v1 = vchangetop(*(ff->vertex[1])), v2 = vchangetop(*(ff->vertex[2]));
if (parallel(p0,p1,p2,v0,v1,v2) && dots_onplane(p0,p1,p2,v0)){
same = true;
break;
}
ff = ff->next;
}
if (!same) ans++;
f = f->next;
} while (f != faces);
return ans;
}
int main(void) {
double x, y, z;
int N;
while (scanf("%d", &N) != EOF) {
vertices = NULL;
edges = NULL;
faces = NULL;
for (int i = 0; i < N; ++i) {
scanf ("%lf %lf %lf", &x, &y, &z );
tVertex v = MakeNullVertex();
v->v[X] = x;
v->v[Y] = y;
v->v[Z] = z;
v->vnum = i;
}
if (N <= 3) printf("0\n");
else {
Solve();
printf("%d\n", FaceArea());
}
}
return 0;
}