UVa 1433 - Aerodynamics
来源:互联网 发布:hadoop2.6源码阅读 编辑:程序博客网 时间:2024/06/05 01:57
这是我第一次使用多个namespace 写程序 , 对于3D和2D要同时出现的题目完全可以把3D中的每一个变量后加一个3 , 但是完全没有下面的写法方便。
训练指南的三维凸包写法非常实用 , 进行些许扰动 , 可以减少很多麻烦。 这个题指明了: no two points coincide , 所以不需要判重
提示:
1. 求凸包
2. 然后关于z的一个平面一个平面的枚举就好了
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <string>#include <vector>#include <deque>#include <stack>#include <algorithm>using namespace std;const double eps = 1e-10;const int maxn = 110;int dcmp(double a) { return fabs(a)<eps?0:(a<0?-1:1); }namespace TwoD{ struct points { double x , y; void read(){ scanf("%lf%lf",&x,&y); } points(double x = 0 , double y = 0):x(x),y(y){} bool operator <(const points& b)const { return dcmp(x-b.x)==-1 || (dcmp(x-b.x)==0 && dcmp(y-b.y)==-1); } bool operator ==(const points& b)const { return dcmp(x-b.x)==0 && dcmp(y-b.y)==0; } }; typedef points Vector; typedef vector<points> polygon; Vector operator +(Vector a , Vector b) { return Vector(a.x+b.x , a.y+b.y); } Vector operator -(Vector a , Vector b) { return Vector(a.x-b.x , a.y-b.y); } Vector operator *(Vector a , double b) { return Vector(a.x*b , a.y*b ); } Vector operator /(Vector a , double b) { return Vector(a.x/b , a.y/b ); } double Cross(Vector a , Vector b) { return a.x*b.y-a.y*b.x; } double Dot(Vector a , Vector b) { return a.x*b.x+a.y*b.y; } points ch[maxn]; int convexHull(polygon p) { sort(p.begin(), p.end()); p.erase(unique(p.begin(), p.end()), p.end()); int n = p.size(); int m = 0; for(int i=0;i<n;i++) { while(m>1 && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]))<=0) m--; ch[m++] = p[i]; } int k = m; for(int i=n-2;i>=0;i--) { while(m>k && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]))<=0) m--; ch[m++] = p[i]; } if(n>1) m--; return m; } double area(int m) { double res = 0; for(int i=1;i<m-1;i++) res+= Cross(ch[i]-ch[0], ch[i+1]-ch[0]); return res/2.0; }};namespace ThreeD{ struct points { double x , y , z; void read(){ scanf("%lf%lf%lf",&x,&y,&z); } points(double x =0 , double y =0 , double z =0 ):x(x),y(y),z(z){} }; typedef points Vector; Vector operator +(Vector a , Vector b) { return Vector(a.x+b.x , a.y+b.y , a.z+b.z); } Vector operator -(Vector a , Vector b) { return Vector(a.x-b.x , a.y-b.y , a.z-b.z); } Vector operator *(Vector a , double b) { return Vector(a.x*b , a.y*b , a.z*b ); } Vector operator /(Vector a , double b) { return Vector(a.x/b , a.y/b , a.z/b ); } double Dot(Vector a , Vector b) { return a.x*b.x+a.y*b.y+a.z*b.z; } Vector Cross(Vector a , Vector b) { return Vector(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 rand01() { return rand() / (double)RAND_MAX; } double randeps() { return (rand01()-0.5)*eps; } points addnoise(points p) { return points(p.x+randeps() , p.y+randeps() , p.z+randeps()); } struct face { int v[3]; face(int v1=0, int v2=0, int v3=0){ v[0] = v1; v[1] = v2; v[2] = v3; } Vector normal(points *p) { return Cross(p[v[1]]-p[v[0]], p[v[2]]-p[v[0]]); } int cansee(points* p , int i) { return Dot(p[i]-p[v[0]] , normal(p))>0?1:0; } }; points p[maxn]; points t[maxn]; int vis[maxn][maxn]; vector<face> convexHull(points* p , int n) { vector<face> res; res.push_back(face(0,1,2)); res.push_back(face(2,1,0)); for(int i=3;i<n;i++) { vector<face> Next; for(int j=0;j<res.size();j++) { int hi = res[j].cansee(p, i); if(!hi) Next.push_back(res[j]); for(int k=0;k<3;k++) vis[res[j].v[k]][res[j].v[(k+1)%3]] = hi; } for(int j=0;j<res.size();j++) for(int k=0;k<3;k++) { int a = res[j].v[k] , b = res[j].v[(k+1)%3]; if(vis[a][b]!=vis[b][a] && vis[a][b]) Next.push_back(face(a,b,i)); } res = Next; } return res; }};using namespace ThreeD;int main(int argc, char *argv[]) { int n , zmin , zmax , Case=0; while(cin>>n>>zmin>>zmax) { if(Case) cout<<endl; Case++; for(int i=0;i<n;i++) p[i].read(); for(int i=0;i<n;i++) t[i] = addnoise(p[i]); vector<face> c = convexHull(t, n); for(int z=zmin;z<=zmax;z++) { TwoD::polygon poly; for(int i=0;i<c.size();i++) for(int j=0;j<3;j++) { int a = c[i].v[j] , b = c[i].v[(j+1)%3]; double z1 = p[a].z , z2 = p[b].z , x1 = p[a].x , x2 = p[b].x , y1 = p[a].y , y2 = p[b].y; if(dcmp(z1-z2)==0) continue; if(dcmp(p[a].z-z)*dcmp(p[b].z-z)<=0) poly.push_back(TwoD::points(x1+(z-z1)/(z2-z1)*(x2-x1) , y1+(z-z1)/(z2-z1)*(y2-y1))); } int m = TwoD::convexHull(poly);// cout<<poly.size()<<" "<<m<<endl; printf("%.5lf\n",TwoD::area(m)); } } return 0;}
程序的时间表现相当优秀:-)
详解:
1. 在枚举每一个平面的时候 , 找到这个平面在凸包上的所有交点 , 然后把这些交点排序 , 这里我用了二维凸包 , 这更加鲁棒
注意:
两个z值相等的线段不做考量 , 那会不会漏掉些点呢? 不会 , 因为每个点会在多个平面中出现 , 所以不用担心
1 0
- UVa 1433 - Aerodynamics
- NEERC 2008 Aerodynamics
- uva
- UVA
- UVA
- UVA
- uva
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- STL中vector iterators imcompatible报错
- SpringMVC深度探险 —— SpringMVC核心配置文件详解
- treap
- 3D Touch详解
- asp.net项目页面间传值的几种方式(部分转载)
- UVa 1433 - Aerodynamics
- 字符编码简介
- 单件模式(heade first设计模式读书笔记)
- Objc 精选 - 3D Touch 之 Peek & Pop 操作
- 编译C51项目的bat脚本
- kettle设计工具spoon安装问题及解决(Win环境)
- 29.iPhone距离传感器的简单使用
- 用TextView动态显示文件内容
- 2013年,年终总结-“波澜”