zoukankan      html  css  js  c++  java
  • bzoj 1209: [HNOI2004]最佳包裹 三维凸包

    1209: [HNOI2004]最佳包裹

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 160  Solved: 58
    [Submit][Status][Discuss]

    Description

    H 公司生产了一种金属制品,是由一些笔直的金属条支撑起来的,金属条和别的金属条在交点上被焊接在了一起。现在由于美观需要,在这个产品用一层特殊的材料包 裹起来。公司为了节约成本,希望消耗的材料最少(不计裁剪时的边角料的损失)。你的程序需要根据给定的输入,给出符合题意的输出: 输入包括该产品的顶点的个数,以及所有顶点的坐标; 你需要根据输入的计算出包裹这个产品所需要的材料的最小面积。 结果要求精确到小数点后第六位。(四舍五入)

    Input

    第1行是一个整数n(4 <= n <= 100),表示顶点的个数;第2行到第n+1行,每行是3个实数xi,yi,zi,表示第i个顶点的坐标。每个顶点的位置各不相同。

    Output

    输出只有一个实数,表示包裹一个该产品所需的材料面积的最小值。

    Sample Input

    4
    0 0 0
    1 0 0
    0 1 0
    0 0 1 说明:该输入示例中共有4个点,可参见后面的图示。


    Sample Output

    2.366025

    HINT

      这道题算是三维凸包的模板题吧,话说网上的三维凸包的教程中判三点共线,四点共面的方法确实有些复杂,经过idy博客的启发,其实在做凸包前对每个点加一遍噪音就行了。如果一个点可以看见当前一个面,那么这个面就会被删除,其表现就是有向体积为负数,删除一个面的同时,删除这个面的三条边(也是有向的)最有扫一遍观察哪些边的反向边不存在,然后将他们的反向边与当前加的点一同构成新的凸包。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<assert.h>
    #include<vector>
    using namespace std;
    #define MAXN 120
    #define eps 1e-11
    typedef double real;
    inline int sgn(real x)
    {
            if (abs(x)<eps)return 0;
            return x<0?-1:1;
    }
    struct point
    {
            real x,y,z;
            point(real x,real y,real z):x(x),y(y),z(z){}
            point(){}
            int read()
            {
                    return scanf("%lf %lf %lf
    ",&x,&y,&z);
            }
            void noise()
            {
                    x+=(real)(rand()%10000-5000)/10000*eps;
                    y+=(real)(rand()%10000-5000)/10000*eps;
                    z+=(real)(rand()%10000-5000)/10000*eps;
            }
            real len()
            {
                    return sqrt(x*x+y*y+z*z);
            }
    };
    typedef point vect;
    struct line
    {
            point ps;
            real x,y,z;
            line(){}
            line(point p1,point p2)
            {
                    ps=p1;
                    x=p2.x-p1.x;
                    y=p2.y-p1.y;
                    z=p2.z-p1.z;
            }
            line(point ps,real x,real y,real z):ps(ps),x(x),y(y),z(z){}
    };
    vect xmul(line l1,line l2)
    {
            return vect(l1.y*l2.z-l1.z*l2.y,l1.z*l2.x-l1.x*l2.z,l1.x*l2.y-l1.y*l2.x);
    }
    real volume(line l1,line l2,line l3)
    {
            return + l1.x*l2.y*l3.z - l1.x*l2.z*l3.y 
                   - l1.y*l2.x*l3.z + l1.y*l2.z*l3.x
                   + l1.z*l2.x*l3.y - l1.z*l2.y*l3.x;
    }
    //+1 2 3
    //-1 3 2
    //-2 1 3
    //+2 3 1
    //+3 1 2
    //-3 2 1
    struct surface
    {
            point ps;
            real x1,y1,z1;
            real x2,y2,z2;
            surface(){}
            surface(point p1,point p2,point p3)
            {
                    ps=p1;
                    x1=p2.x-p1.x,y1=p2.y-p1.y,z1=p2.z-p1.z;
                    x2=p3.x-p1.x,y2=p3.y-p1.y,z2=p3.z-p1.z;
            }
            real volume(point pt)
            {
                    return ::volume(line(ps,pt),line(ps,x1,y1,z1),line(ps,x2,y2,z2));
            }
            vect nvect()
            {
                    return xmul(line(ps,x1,y1,z1),line(ps,x2,y2,z2));
            }
            void reverse()
            {
                    swap(x1,x2);
                    swap(y1,y2);
                    swap(z1,z2);
            }
    };
    point pl[MAXN];
    struct face
    {
            int pt[3];
            face(int x,int y,int z)
            {
                    pt[0]=x;pt[1]=y;pt[2]=z;
            }
            surface ToSurface()
            {
                    return surface(pl[pt[0]],pl[pt[1]],pl[pt[2]]);
            }
            void print()
            {
                    printf("Face:%d %d %d
    ",pt[0],pt[1],pt[2]);
            }
    };
    vector<face> cc;
    vector<pair<int,int> > chs;
    bool status[MAXN][MAXN];
    int main()
    {
            freopen("input.txt","r",stdin);
            int n;
            scanf("%d",&n);
            for (int i=0;i<n;i++)
                    pl[i].read();
            for (int i=0;i<n;i++)
                    pl[i].noise();
        /*    for (int i=0;i<n;i++)
                    swap(pl[rand()%n],pl[rand()%n]);*/
            cc.push_back(face(0,1,2));
            cc.push_back(face(2,1,0));
            for (int i=0;i<3;i++)
                    status[i][(i+1)%3]=true;
            for (int i=1;i<4;i++)
                    status[i%3][i-1]=true;
            for (int i=3;i<n;i++)
            {
                    //for (int j=0;j<cc.size();j++)cc[j].print();    printf("
    ");
                    chs.clear();
                    for (int j=0;j<cc.size();j++)
                    {
                            if (cc[j].ToSurface().volume(pl[i])<0)
                            {
                                    for (int k=0;k<3;k++)
                                    {
                                            status[cc[j].pt[k]][cc[j].pt[(k+1)%3]]=false;
                                            chs.push_back(make_pair(cc[j].pt[k],cc[j].pt[(k+1)%3]));
                                    }
                                    swap(cc[j],cc[cc.size()-1]);
                                    cc.pop_back();
                                    j--;
                            }
                    }
                    for (int j=0;j<chs.size();j++)
                    {
                            if (!status[chs[j].first][chs[j].second] && status[chs[j].second][chs[j].first])continue;
                            chs[j]=chs[chs.size()-1];
                            j--;
                            chs.pop_back();
                    }
                    for (int j=0;j<chs.size();j++)
                    {
                            cc.push_back(face(i,chs[j].first,chs[j].second));
                            status[i][chs[j].first]=status[chs[j].first][chs[j].second]=status[chs[j].second][i]=true;
                    }
                    for (int j=0;j<n;j++)
                            for (int k=0;k<n;k++)
                                    assert(!(status[j][k]^status[k][j]));
            }
            //for (int j=0;j<cc.size();j++)cc[j].print();    printf("
    ");
            real ans=0;
            for (int i=0;i<cc.size();i++)
                    ans+=cc[i].ToSurface().nvect().len()/2;
            printf("%.6lf
    ",abs(ans));
    }
  • 相关阅读:
    OCS边缘服务器部署(包含ISA设置)
    RMS部署文档
    推荐软件:PowerShell Plus
    OCS排错工具和最佳实践
    在Exchange Server 2007中使用多主机名称证书
    OCS边缘服务器部署
    推荐软件:Quset PowerGUI
    ISA 2008(FOREFRONT TMG)安装体验
    gridview 删除确认
    标识列 在任意编号位置插入数据
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4440868.html
Copyright © 2011-2022 走看看