列表

详情


NC20036. [HNOI2004]最佳包裹

描述

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

输入描述

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

输出描述

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

示例1

输入:

4
0 0 0
1 0 0
0 1 0
0 0 1

输出:

2.366025

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 3ms, 内存消耗: 552K, 提交时间: 2020-09-12 14:19:52

#include<bits/stdc++.h>
#define eps 1e-11
using namespace std;

struct Point3
{
    double x,y,z;
    Point3 (double x=0,double y=0,double z=0):x(x),y(y),z(z){}
};

typedef Point3 Vector3;
const int N=510;

Vector3 operator + (Vector3 A, Vector3 B){return Vector3{A.x+B.x,A.y+B.y,A.z+B.z};}
Vector3 operator - (Vector3 A, Vector3 B){return Vector3{A.x-B.x,A.y-B.y,A.z-B.z};}
Vector3 operator * (Vector3 A, double B){return Vector3{A.x*B,A.y*B,A.z*B};}
Vector3 operator / (Vector3 A, double B){return Vector3{A.x/B,A.y/B,A.z/B};}

double Dot(Vector3 A, Vector3 B){return A.x*B.x+A.y*B.y+A.z*B.z;}
Vector3 Cross(Vector3 A,Vector3 B) {return Vector3(A.y*B.z-A.z*B.y,A.z*B.x-A.x*B.z,A.x*B.y-A.y*B.x);}
double len(Vector3 A){return sqrt(Dot(A,A));}
double angle(Vector3 A, Vector3 B){return acos(Dot(A,B)/len(A)/len(B));}

double rand01(){return rand()/(double)RAND_MAX;}
double randeps(){return (rand01()-0.5)*eps;}
Point3 add_noise(Point3 p){return Point3{p.x+randeps(),p.y+randeps(),p.z+randeps()};}

struct Face{
    int v[3];
    Vector3 normal(Point3 *P)const{
        return Cross(P[v[1]]-P[v[0]],P[v[2]]-P[v[0]]);
    }
    int cansee(Point3 *P,int i)const{
        return Dot(P[i]-P[v[0]],normal(P))>0?1:0;
    }
};

vector<Face>F;
Point3 P[N],Q[N];

vector<Face> CH3D(Point3 *P,int n){
    vector<Face> cur;
    int vis[N][N];
    cur.push_back((Face){0,1,2});
    cur.push_back((Face){2,1,0});
    for(int i=3;i<n;i++){
        vector<Face> next;
        for(int j=0;j<cur.size();j++){
            Face &f=cur[j];
            int res=f.cansee(P,i);
            if(!res) next.push_back(f);
            for(int k=0;k<3;k++) vis[f.v[k]][f.v[(k+1)%3]]=res;
        }
        for(int j=0;j<cur.size();j++){
            for(int k=0;k<3;k++){
                int a=cur[j].v[k],b=cur[j].v[(k+1)%3];
                if(vis[a][b]!=vis[b][a]&&vis[a][b]) next.push_back((Face){a,b,i});
            }
        }
        cur=next;
    }
    return cur;
}

//三角形面积*2
double S(Point3 a,Point3 b,Point3 c) {
    return len(Cross(b-a,c-a));    //注意要取lenth
}
//四面体有向体积*6  混合积
double V(Point3 a,Point3 b,Point3 c,Point3 d) {
    return Dot(d-a,Cross(b-a,c-a));
}
//表面积
double Ssum(Point3 *P,int n) {
    double ans=0;
    if (n==3) {
        ans=S(P[0],P[1],P[2]);
        return ans/2.0;
    }
    for (int i=0;i<F.size();i++)
        ans=ans+S(P[F[i].v[0]],P[F[i].v[1]],P[F[i].v[2]])/2.0;
    return ans;
}
//体积
double Vsum(Point3 *P) {
    double ans=0;
    Point3 tmp(0,0,0);
    for (int i=0;i<F.size();i++)
        ans+=V(tmp,P[F[i].v[0]],P[F[i].v[1]],P[F[i].v[2]]);
    return fabs(ans/6.0);
}
bool same(int s,int t,Point3 *P) {
    Point3 &a=P[F[s].v[0]];
    Point3 &b=P[F[s].v[1]];
    Point3 &c=P[F[s].v[2]];
    return fabs(V(a,b,c,P[F[t].v[0]]))<eps &&
            fabs(V(a,b,c,P[F[t].v[1]]))<eps &&
            fabs(V(a,b,c,P[F[t].v[2]]))<eps;
}
//表面多边形个数
int facecnt(Point3 *P) {
    int flag,ans=0;
    for (int i=0;i<F.size();i++) {
        flag=1;
        for (int j=0;j<i;j++)
            if (same(i,j,P)) {
                flag=0;
                break;
            }
        ans+=flag;
    }
    return ans;
}
//三维凸包重心
Point3 centre(Point3 *P) {
    Point3 ans(0,0,0),o(0,0,0);
    double all=0;
    for (int i=0;i<F.size();i++) {
        double vol=V(o,P[F[i].v[0]],P[F[i].v[1]],P[F[i].v[2]]);
        ans=ans+(o+P[F[i].v[0]]+P[F[i].v[1]]+P[F[i].v[2]])/4.0*vol;
        all+=vol;
    }
    ans=ans/all;
    return ans;
}
//点到面的距离
double dis_face(Point3 p,Point3 *P,int i) {
    return fabs(V(P[F[i].v[0]],P[F[i].v[1]],P[F[i].v[2]],p)/len(Cross(P[F[i].v[1]]-P[F[i].v[0]],P[F[i].v[2]]-P[F[i].v[0]])));
}

int main()
{
    int n;
    scanf("%d",&n);
    for (int i=0;i<n;i++)
        scanf("%lf%lf%lf",&P[i].x,&P[i].y,&P[i].z);
    for(int i=0;i<n;i++) Q[i]=add_noise(P[i]);
    F=CH3D(Q,n);
    printf("%.6f\n",fabs(Ssum(P,n)));
    return 0;
}

C++ 解法, 执行用时: 3ms, 内存消耗: 436K, 提交时间: 2021-09-09 21:37:00

#include<bits/stdc++.h>

using namespace std;
typedef pair<double,double>pdd;
#define x first
#define y second
const int N = 250;
const double eps = 1e-12;
const double pi = acos(-1);

bool g[N][N];
int n,m;

double rand_eps(){
    return ((double)rand() / RAND_MAX - 0.5) * eps;
}

struct Point{
    double x,y,z;
    void skank(){
        x+=rand_eps();y+=rand_eps();z+=rand_eps();
    }
    Point operator + (Point b){
        return {x+b.x,y+b.y,z+b.z};
    }
    Point operator - (Point b){
        return {x-b.x,y-b.y,z-b.z};
    }
    Point operator * (Point b){
        return {y*b.z - b.y*z,z*b.x - b.z*x, x*b.y - y*b.x}; 
    }
    double operator & (Point t){
        return x*t.x+y*t.y+z*t.z;
    }
    double len(){
        return sqrt(x*x+y*y+z*z);
    }
}q[N];

struct Plane{
    int v[3];
    Point norm(){
        return (q[v[1]] - q[v[0]]) * (q[v[2]] - q[v[0]]);
    }
    double area(){
        return norm().len() / 2;
    }
    bool above(Point a){
        return ((a- q[v[0]]) & norm()) >= 0;
    }
}plane[N], np[N]; 

void get_conx_3d(){
    plane[m++] = {0,1,2};
    plane[m++] = {2,1,0};
    for(int i=3;i<n;i++){
        int cnt=0;
        for(int j=0;j<m;j++){
            bool t = plane[j].above(q[i]);
            if(!t)np[cnt++] = plane[j];
            for(int k=0;k<3;k++){
                g[plane[j].v[k]][plane[j].v[(k+1)%3]] = t;
            }
        }
        for(int j=0;j<m;j++){
            for(int k=0;k<3;k++){
                int a = plane[j].v[k], b = plane[j].v[(k+1)%3];
                if(g[a][b] && !g[b][a]){
                    np[cnt++] = {a,b,i};
                }
            }
        }
        m = cnt;
        for(int j=0;j<m;j++)plane[j] = np[j];
    }
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>q[i].x>>q[i].y>>q[i].z;
        q[i].skank();
    }
    get_conx_3d();

    double ans=0;
    for(int i=0;i<m;i++){
        ans+=plane[i].area();
    }
    printf("%lf",ans);
    return 0;
}

上一题