hdu 3662 3D Convex Hull (三维凸包 模板1)


题目链接: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值