HDU 4449 Building Design 第37届ACM/ICPC 金华赛区H题 (计算几何,三维凸包+空间坐标旋转+二维凸包)
2012-11-07 21:36
639 查看
Building Design
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 431 Accepted Submission(s): 117
[align=left]Problem Description[/align]
You are a notable architect.
Recently, a company invites you to design their new building for them. It is not an easy task, because they make some strange claims to the new building:
1.Its shape should be the same as a convex polyhedron which they have given to you, though you can rotate it arbitrarily.
2.One face of the building should cling to the ground. (Of course! Have you ever seen a building only touch the ground by an edge, or a point, or even suspend in the air?)
3.They want the building to be as striking as possible. We call the highest point of the building as the “peak”. The higher the peak is the more striking the building will be.
4.If there are many designs meet all claims above, the occupied land of the building should be less. In another word, the building's vertical projection area on the ground should be as small as possible.
Now, give you the relative positions of vertices of the building, please design the building and tell them H – the height of the peak, as well as S - the projection area of the building in your best design.
[align=left]Input[/align]
There are several test cases in the input.
Each test case begins with one integer n (1 ≤ n ≤ 50), indicating the number of vertices of the building.
Then n lines follow. Each line contains three integers x, y, z (-10000 ≤ x, y, z ≤ 10000), separated by spaces, indicating the relative positions of one vertex of the building.
The input ends with n = 0.
[align=left]Output[/align]
For each test case, output two float numbers H and S in one line, separated by one space.
Please round the results to three digits after decimal point.
[align=left]Sample Input[/align]
6 1 0 0 -1 0 0 0 1 0 0 -1 0 0 0 1 0 0 -1 0
[align=left]Sample Output[/align]
1.155 1.732
[align=left]Source[/align]
2012 Asia JinHua Regional Contest
[align=left]Recommend[/align]
zhuyuanchen520
题目就是给了一个凸多面题。
要把这个凸多面体放到地上,一个面要接触到地面。
求一种放法,使得最高点最高,最高点相同时使投影面积最小。输出最高点高度H和投影面积S。
先三维凸包一下求得所有的三角形表面。
然后枚举每一个表面,进行坐标变换,旋转使得这个表面变水平,然后投影求投影面积,算最高点高度。
题目的数据好像没有n==1 ,2,3的情况,可以忽略。
有个问题就是如果按照旋转之后的z坐标值来算高度的话,会产生很大的精度差。最好就是直接算点到面的距离。
//============================================================================ // Name : Building.cpp // Author : kuangbin // Version : // Copyright : Your copyright notice // Description : HDU 4449 // 三维凸包+二维凸包+三维坐标旋转变换 //============================================================================ #include <iostream> #include <string.h> #include <math.h> #include <algorithm> #include <stdio.h> #include <vector> #include <map> #include <set> #include <queue> using namespace std; const int MAXN = 110; const double eps=1e-8; const double PI=acos(-1.0); inline int sign(double p) { if(p>eps)return 1; else if(p<-eps)return -1; else return 0; } struct Point { double x,y,z; Point(double xx=0,double yy=0,double zz=0):x(xx),y(yy),z(zz){} Point operator +(const Point p1) { return Point(x+p1.x,y+p1.y,z+p1.z); } Point operator -(const Point p1) { return Point(x-p1.x,y-p1.y,z-p1.z); } Point operator *(const Point p1) { return Point(y*p1.z-z*p1.y,z*p1.x-x*p1.z,x*p1.y-y*p1.x); } Point operator *(double d) { return Point(d*x,d*y,d*z); } Point operator /(double d) { return Point(x/d,y/d,z/d); } double operator ^(const Point p1) { return x*p1.x+y*p1.y+z*p1.z; } double getLen() { return sqrt(x*x+y*y+z*z); } void read() { scanf("%lf%lf%lf",&x,&y,&z); } }; struct face { int a,b,c; bool ok; }; struct CH3D { int n;//初始顶点数 Point P[MAXN];//初始顶点 int num;//凸包表面的三角形个数 face F[8*MAXN];//凸包表面的三角形 int g[MAXN][MAXN]; double vlen(Point a) { return sqrt(a.x*a.x+a.y*a.y+a.z*a.z); } Point cross(Point a,Point b,Point c) { return Point( (b.y-a.y)*(c.z-a.z)-(b.z-a.z)*(c.y-a.y), (b.z-a.z)*(c.x-a.x)-(b.x-a.x)*(c.z-a.z), (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x) ); } //三角形面积*2 double area(Point a,Point b,Point c) { return vlen((b-a)*(c-a)); } //四面体面积*6 double volume(Point a,Point b,Point c,Point d) { return ((b-a)*(c-a))^(d-a); } double dblcmp(Point &p,face &f) { Point m=P[f.b]-P[f.a]; Point n=P[f.c]-P[f.a]; Point t=p-P[f.a]; return (m*n)^t; } void deal(int p,int a,int b) { int f=g[a][b]; face add; if(F[f].ok) { if(dblcmp(P[p],F[f])>eps) dfs(p,f); else { add.a=b; add.b=a; add.c=p; add.ok=true; g[p][b]=g[a][p]=g[b][a]=num; F[num++]=add; } } } void dfs(int p,int now) { F[now].ok=false; deal(p,F[now].b,F[now].a); deal(p,F[now].c,F[now].b); deal(p,F[now].a,F[now].c); } bool same(int s,int t) { Point &a=P[F[s].a]; Point &b=P[F[s].b]; Point &c=P[F[s].c]; return fabs(volume(a,b,c,P[F[t].a]))<eps && fabs(volume(a,b,c,P[F[t].b]))<eps && fabs(volume(a,b,c,P[F[t].c]))<eps; } void create() { int i,j,tmp; face add; num=0; if(n<4)return; bool flag=true; for(i=1;i<n;i++) { if(vlen(P[0]-P[i])>eps) { swap(P[1],P[i]); flag=false; break; } } if(flag)return; flag=true; for(i=2;i<n;i++) { if(vlen((P[0]-P[1])*(P[1]-P[i]))>eps) { swap(P[2],P[i]); flag=false; break; } } if(flag)return; flag=true; for(i=3;i<n;i++) { if(fabs((P[0]-P[1])*(P[1]-P[2])^(P[0]-P[i]))>eps) { swap(P[3],P[i]); flag=false; break; } } if(flag)return; for(i=0;i<4;i++) { add.a=(i+1)%4; add.b=(i+2)%4; add.c=(i+3)%4; add.ok=true; if(dblcmp(P[i],add)>0)swap(add.b,add.c); g[add.a][add.b]=g[add.b][add.c]=g[add.c][add.a]=num; F[num++]=add; } for(i=4;i<n;i++) { for(j=0;j<num;j++) { if(F[j].ok && dblcmp(P[i],F[j])>eps) { dfs(i,j); break; } } } tmp=num; for(i=num=0;i<tmp;i++) if(F[i].ok) F[num++]=F[i]; } double ptoface(Point p,int i) { return fabs(volume(P[F[i].a],P[F[i].b],P[F[i].c],p)/vlen((P[F[i].b]-P[F[i].a])*(P[F[i].c]-P[F[i].a]))); } }; CH3D hull; Point ps[MAXN]; int n; inline Point get_point(Point st,Point ed,Point tp) { double t1=(tp-st)^(ed-st); double t2=(ed-st)^(ed-st); double t=t1/t2; Point ans=st + ((ed-st)*t); return ans; } inline double dist(Point st,Point ed) { return sqrt((ed-st)^(ed-st)); } Point rotate(Point st,Point ed,Point tp,double A) { Point root=get_point(st,ed,tp); Point e=(ed-st)/dist(ed,st); Point r=tp-root; Point vec=e*r; Point ans=r*cos(A)+vec*sin(A)+root; return ans; } struct point { double x,y; }; point list[MAXN]; int stack[MAXN],top; double cross(point p0,point p1,point p2) { return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } double dis(point p1,point p2) { return sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(point p1,point p2) { double tmp=cross(list[0],p1,p2); if(sign(tmp)>0)return true; else if(sign(tmp)==0 && dis(list[0],p1)<dis(list[0],p2))return true; else return false; } void init(int n) { point p0; p0=list[0]; int k=0; for(int i=1;i<n;i++) { if( (p0.y+eps > list[i].y) || ( sign(p0.y-list[i].y)==0 && (p0.x+eps > list[i].x))) { p0=list[i]; k=i; } } list[k]=list[0]; list[0]=p0; sort(list+1,list+n,cmp); } void graham(int n) { init(n); if(n==1) { top=0; stack[0]=0; return; } if(n==2) { top=1; stack[0]=0; stack[1]=1; return; } for(int i=0;i<=1;i++)stack[i]=i; top=1; for(int i=2;i<n;i++) { while(top>0 && cross(list[stack[top-1]],list[stack[top]],list[i])<=eps) top--; top++; stack[top]=i; } } bool input() { scanf("%d",&n); if(n==0)return false; hull.n=n; for(int i=0;i<n;i++) hull.P[i].read(); return true; } void solve() { double ansH=0,ansS=1e200; double H,S; if(n<=2)//该题数据好像没有这种情况 { printf("0.000 0.000\n"); return; } if(n==3)//该题数据好像没有这种情况 { ansH=0; ansS=(hull.P[1]-hull.P[0])^(hull.P[2]-hull.P[0]); ansS/=2.0; printf("%.3lf %.3lf\n",ansH,ansS); return; } hull.create(); for(int i=0;i< hull.num;i++) { for(int j=0;j<n;j++)ps[j]=hull.P[j]; Point p1=(ps[hull.F[i].b]-ps[hull.F[i].a])*(ps[hull.F[i].c]-ps[hull.F[i].a]); Point e(0,0,1); Point vec=p1*e; double A=p1^e/p1.getLen(); A=acos(A); if(sign(A)!=0 && sign(A-PI)!=0) { Point p0(0,0,0); for(int j=0;j<n;j++) ps[j]=rotate(p0,vec,ps[j],A); } double tt=ps[hull.F[i].a].z; for(int j=0;j<n;j++) ps[j].z -= tt; H=0; for(int j=0;j<n;j++) { //H=max(H,fabs(ps[j].z)+0.00001);//这个有精度差,一直会WA H=max(H,hull.ptoface(hull.P[j],i)); //if( fabs(hull.ptoface(hull.P[j],i)-fabs(ps[j].z))>=0.00000005)while(1); //加了上面这句不超时,说明两者很接近了,由于精度问题会一直WA } //for(int j=0;j<n;j++) // H=max(H,hull.ptoface(hull.P[j],i)); for(int j=0;j<n;j++) { list[j].x=ps[j].x; list[j].y=ps[j].y; } graham(n); S=0; for(int j=0;j<top;j++) S+=(list[stack[j]].x*list[stack[j+1]].y - list[stack[j]].y*list[stack[j+1]].x); S+=(list[stack[top]].x*list[stack[0]].y - list[stack[top]].y*list[stack[0]].x); S=fabs(S); S/=2; if(H > ansH || ( sign(H-ansH)==0 && ansS > S )) { ansH=H; ansS=S; } } printf("%.3lf %.3lf\n",ansH,ansS); } int main() { while(input())solve(); return 0; }
相关文章推荐
- POJ4449(三维凸包+空间坐标旋转+二维凸包)
- HDU 4449 Building Design 三维凸包+空间坐标变换
- ACM-ICPC(2017)北京赛区网络赛-E-Territorial Dispute(计算几何->凸包)
- HDU 4273 Rescue 第37届ACM/ICPC 长春赛区网络赛1007题(三维凸包+重心+点面距离)
- HDU 3692 Shade of Hallelujah Mountain (计算几何,三维空间点的旋转,二维凸包)
- HDU 4573 Throw the Stones(动态三维凸包)(2013 ACM-ICPC长沙赛区全国邀请赛)
- 第37届ACM/ICPC 金华赛区现场赛最水四道题 HDU 4442 Physical Examination HDU 4450 Draw Something HDU 4451 Dressing HDU 4452 Running Rabbits
- HDU 4279 Number 第37届ACM/ICPC天津赛区网络赛1002题 (简单规律题)
- HDU 4407 Sum 第37届ACM/ICPC 金华赛区 第1008题 (容斥原理)
- Substrings 第37届ACM/ICPC 杭州赛区现场赛C题(hdu 4455)
- HDU 4405 Aeroplane chess 第37届ACM/ICPC 金华赛区网络赛(递推求期望)
- HDU 5581 Infinity Point Sets ACM/ICPC 2015 上海区域赛 I 计算几何+组合计数
- HDU 5572 An Easy Physics Problem(计算几何)——2015ACM/ICPC亚洲区上海站-重现赛
- HDU 4438 Hunters 第37届ACM/ICPC 天津赛区现场赛H题(超级水的题目)
- HDU 4403 A very hard Aoshu problem 第37届ACM/ICPC 金华赛区网络赛1004题
- HDU 4417 Super Mario 第37届ACM/ICPC 杭州赛区网络赛1008题(树状数组或者线段树)
- HDU 4455 Substrings 第37届ACM/ICPC 杭州赛区现场赛 C题 (DP)
- HDU 4431 Mahjong 第37届ACM/ICPC 天津赛区现场赛A题 (枚举,判断麻将胡牌)
- 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 GSM Base Station Identification 线性变换||计算几何
- HDU 4276 The Ghost Blows Light 第37届ACM/ICPC长春赛区1010题 (树形DP)