POJ 2451 Uyuw's Concert(半平面交求面积)
http://poj.org/problem?id=2451
题意:
给你一个矩形框(左下角[0,0],右上角[10000,10000]),然后给你n条从(x1,y1)到(x2,y2)的有向直线(测试得出直线方向). 问你这些有向直线的左边的交集面积(处于矩形框内的)有多大.
分析:
很明显的半平面交问题了,首先添加4条带方向直线:
点: (0, 0) , 方向向量: (10000, 0)
点: (10000, 0) , 方向向量: (0, 10000)
点: (10000, 10000) , 方向向量: (-10000, 0)
点: (0, 10000) , 方向向量: (0, -10000)
然后对于每个输入直线(x1,y1)和(x2,y2). 添加对应直线:
点: (x1,y1), 方向向量: (x2-x1,y2-y1)
最终求出半平面交的凸多边形即可(本题要么不存在半平面交的部分,要么一定是凸多边形. 不会出现无界区域).
然后输出该凸多边形的面积.
AC代码: 要用C++提交, G++提交有精度问题
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; //精度控制 const double eps=1e-10; int dcmp(double x) { if(fabs(x)<eps) return 0; return x<0?-1:1; } //点 struct Point { double x,y; Point(){} Point(double x,double y):x(x),y(y){} }; //向量 typedef Point Vector; //点-点==向量 Vector operator-(Point A,Point 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 p) { return Vector(A.x*p, A.y*p); } //叉积 double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x; } //多边形面积 double PolygonArea(Point *p,int n) { double area=0; for(int i=1;i<n-1;i++) area += Cross(p[i]-p[0],p[i+1]-p[0]); return fabs(area)/2; } //带方向直线 struct Line { Point p; Vector v; double ang; Line(){} Line(Point p,Vector v):p(p),v(v) { ang=atan2(v.y,v.x); } bool operator<(const Line& rhs)const { return ang<rhs.ang; } }; //判断点P是否在直线L左边 bool OnLeft(Line L,Point p) { return Cross(L.v,p-L.p)>0; } //求直线交点 Point GetIntersection(Line a,Line b) { Vector u=a.p-b.p; double t=Cross(b.v,u)/Cross(a.v,b.v); return a.p+a.v*t; } //求半平面交 int HalfplaneIntersection(Line *L,int n,Point *poly) { sort(L,L+n); int first=0,last=0; Point *p=new Point[n]; Line *q=new Line[n]; q[0]=L[0]; for(int i=1;i<n;i++) { while(first<last && !OnLeft(L[i],p[last-1])) last--; while(first<last && !OnLeft(L[i],p[first])) first++; q[++last]=L[i]; if(fabs(Cross(q[last].v,q[last-1].v))<eps) { last--; if(OnLeft(q[last],L[i].p)) q[last]=L[i]; } if(first<last) p[last-1]=GetIntersection(q[last],q[last-1]); } while(first<last && !OnLeft(q[first], p[last-1])) last--; if(last-first<=1) return 0; p[last]=GetIntersection(q[last],q[first]); int m=0; for(int i=first;i<=last;i++) poly[m++]=p[i]; return m; } /***以上为刘汝佳模板***/ const int maxn=20000+10; Point p[maxn],poly[maxn]; Line L[maxn]; int main() { int n; while(scanf("%d",&n)==1) { n+=4; L[0]=Line(Point(0,0) ,Vector(10000,0)); L[1]=Line(Point(10000,0) ,Vector(0,10000)); L[2]=Line(Point(10000,10000) ,Vector(-10000,0)); L[3]=Line(Point(0,10000) ,Vector(0,-10000)); for(int i=4;i<n;i++) { Point p1,p2; scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y); L[i]=Line(p1,p2-p1); } int m=HalfplaneIntersection(L,n,poly); double ans=0; if(m>0) ans=PolygonArea(poly,m); printf("%.1lf\n",ans); } return 0; }