BZOJ 1209([HNOI2004]最佳包裹-三维凸包)

时间:2022-12-16 15:12:55

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

裸的三维凸包,板子题

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <cstdlib>
#include <queue>
#include <stack>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
For(j,m-1) cout<<a[i][j]<<' ';\
cout<<a[i][m]<<endl; \
}
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
ll sqr(ll a){return a*a;}
double sqr(double a){return a*a;}
ld PI = 3.141592653589793238462643383;
const double eps=1e-11;
int dcmp(double x) {
if (fabs(x)<eps) return 0; else return x<0 ? -1 : 1;
}
struct P3{
double x,y,z;
P3(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
};
typedef P3 V3;
V3 operator+(V3 A,V3 B) {
return V3(A.x+B.x, A.y+B.y ,A.z+B.z);
}
V3 operator-(V3 A,V3 B) {
return V3(A.x-B.x, A.y-B.y ,A.z-B.z );
}
V3 operator*(V3 A,double p) {
return V3(A.x*p, A.y*p, A.z*p);
}
V3 operator/(V3 A,double p) {
return V3(A.x/p, A.y/p, A.z/p);
}
double Dot(V3 A,V3 B) {return A.x*B.x + A.y*B.y + A.z*B.z; }
double Length(V3 A) {return sqrt(Dot(A,A));}
double Angle(V3 A,V3 B){return acos(Dot(A, B)) / Length(A) / Length(B); }
bool operator==(const P3& a,const P3& b) {
return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y) == 0 && dcmp(a.z-b.z) == 0;
}
V3 Cross(V3 A,V3 B) {
return V3(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 Area2(P3 A,P3 B,P3 C) {return Length(Cross(B-A,C-A));}
struct Face{
int v[3];
V3 normal(P3 *p) const {
return Cross(p[v[1]]-p[v[0]], p[v[2]]-p[v[0]]);
}
int cansee(P3 *p, int i) const {
return Dot(p[i] - p[v[0]], normal(p))>0? 1 : 0;
}
};
bool vis[1000][1000];
vector<Face> CH3D(P3 *p, int n) {
MEM(vis);
vector<Face> cur;
cur.pb((Face){{0,1,2}});
cur.pb((Face){{2,1,0}});
Fork(i,3,n-1) {
vector<Face> next;
int sz=SI(cur);
Rep(j,sz) {
Face &f = cur[j];
int res = f.cansee(p, i);
if (!res) next.pb(f);
Rep(k,3) vis[f.v[k]][f.v[(k+1)%3]] = res;
}
Rep(j,sz)
Rep(k,3) {
int a=cur[j].v[k], b=cur[j].v[(k+1)%3];
if (vis[a][b]!= vis[b][a] && vis[a][b]) {
next.pb((Face) {a, b, i});
}
}
cur = next;
}
return cur;
}
P3 read_point3() {
P3 a;
scanf("%lf%lf%lf",&a.x,&a.y,&a.z);
return a;
}
P3 p[1000];
double rand01() {return rand()/(double)RAND_MAX;}
double randeps() {return (rand01()-0.5)*eps; }
P3 add_noise(P3 p) {
return P3(p.x+randeps(),p.y+randeps(),p.z+randeps());
}
int main()
{
// freopen("bzoj1209.in","r",stdin);
// freopen(".out","w",stdout);
int n=read();
Rep(i,n) p[i]= read_point3();
Rep(i,n) p[i]=add_noise(p[i]);
vector<Face> vvv = CH3D(p,n);
int m=SI(vvv);double S=0;
Rep(i,m) {
S+=Area2(p[vvv[i].v[0] ],p[vvv[i].v[1] ],p[vvv[i].v[2] ])/2;
// cout<<vvv[i].v[0]<<' '<<vvv[i].v[1]<<' '<<vvv[i].v[2]<<endl;
}

printf("%.6lf\n",S);
return 0;
}