zoj 1369

来源:互联网 发布:nginx与zookeeper 编辑:程序博客网 时间:2024/06/06 02:08

裸的半平面交。

这个题没说输入是顺时针还是逆时针,可以用面积判断,多边形面积如果是顺时针,面积为负,改变下方向即可。

 

粘两个模板。

code 1:

//书27页 #include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cmath>using namespace std;#define MAXN 1510const double EPS=1e-12;//半平面为向量表示,平面维宇向量左侧struct point{       double x,y; } convex[MAXN];struct line{       point a,b;       double ang; //角度(弧度)        }l[MAXN],st[MAXN];int n,ccnt; double  operator *(const point &x,const point &y)//向量叉乘3 { return x.x*y.y-x.y*y.x; } point operator -(point x,const point &y) //向量减法 { x.x-=y.x,x.y-=y.y;    return x; } point operator *(const line &x,const line &y)//直线求交点  { double a1=(y.b-x.a)*(y.a-x.a),a2=(y.a-x.b)*(y.b-x.b);   point r;   r.x=(x.a.x*a2+x.b.x*a1)/(a2+a1);   r.y=(x.a.y*a2+x.b.y*a1)/(a2+a1);   return r; } bool  operator ==(const point &a,const point &b)//判断共点  { return fabs(a.x-b.x)<EPS&&fabs(a.y-b.y)<EPS; } bool operator <(const line &x,const line &y)//为极角排序重载的运算符{  if(fabs(x.ang-y.ang)<EPS)  return (y.b-x.a)*(x.b-y.a)>EPS;  return x.ang<y.ang;}bool judgeout(const line &x,const point &p)//判断点和平面的关系{return (p-x.a)*(x.b-x.a)>EPS; }bool parellel(const line &x,const line &y)//判断两个向量是否平行{ return fabs((x.b-x.a)*(y.b-y.a))<-EPS; }void inputdata(){  scanf("%d",&n);  scanf("%lf%lf",&l[0].b.x,&l[0].b.y);   l[n-1].a.x=l[0].b.x,l[n-1].a.y=l[0].b.y;  for(int i=1;i<n;i++)  {    scanf("%lf%lf",&l[i].b.x,&l[i].b.y);    l[i-1].a.x=l[i].b.x,l[i-1].a.y=l[i].b.y;  }  for(int i=0;i<n;i++)    l[i].ang=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);}double hplaneintersection(){  int top=1,bot=0;  sort(l,l+n); //极角排序   int tmp=1;   for(int i=1;i<n;++i)    if(l[i].ang-l[i-1].ang>EPS) l[tmp++]=l[i];//去重     n=tmp;    st[0]=l[0],st[1]=l[1];    for(int i=2;i<n;++i)    {       if(parellel(st[top],st[top-1])||parellel(st[bot],st[bot+1]))  return 0;       while(bot<top&&judgeout(l[i],st[top]*st[top-1])) top--;       while(bot<top&&judgeout(l[i],st[bot]*st[bot+1])) bot++;     st[++top]=l[i];    }    while((bot<top&&judgeout(st[bot],st[top]*st[top-1]))) top--;    while((bot<top&&judgeout(st[top],st[bot]*st[bot+1])))bot++;     if(top<bot+1) return 0.00;     st[++top]=st[bot];    ccnt=0;    for(int i=bot;i<top;i++)    convex[ccnt++]=st[i]*st[i+1];    double ans=0;    convex[ccnt]=convex[0];    for(int i=0;i<ccnt;i++)    ans+=convex[i]*convex[i+1];    return ans/2;}double chackdirection(){ double ans=0; for(int i=0;i<n;++i) ans+=l[i].a*l[i].b; return ans;}void changedirection(){  for(int i=0;i<n;++i)  swap(l[i].a,l[i].b);}int main(){    int t;    scanf("%d",&t);    while(t--)    {      inputdata();      if(chackdirection()<0)  changedirection();      printf("%.2f\n",hplaneintersection());    } return 0;} 


code 2:

 

/*半平面交。解释下这个算法哈,其实用笔模拟一下就懂了。它是在一层一层缩小这个区域。外层循环是用每一条边,筛选能看到它的点(或者说是内层形成的边吧),如果看不到(也就是内层有边得两点在他的两侧),那么就求这条边和当前内层循环边的交点作为核的点。交点是肯定能看到的啦。所以内层循环结束一次,点集就要变一次。*/#include <queue>#include <stack>#include <math.h>#include <stdio.h>#include <stdlib.h>#include <iostream>#include <limits.h>#include <string.h>#include <string>#include <algorithm>using namespace std;const int MAX = 1510;struct point{ double x,y;};point p[MAX],s[MAX];const double eps = 1e-6;bool dy(double x,double y){return x > y + eps;}// x > y bool xy(double x,double y){return x < y - eps;}// x < y bool dyd(double x,double y){ return x > y - eps;}// x >= y bool xyd(double x,double y){return x < y + eps;} // x <= y bool dd(double x,double y) {return fabs( x - y ) < eps;}  // x == ydouble crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 {return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);}point l2l_inst_p(point u1,point u2,point v1,point v2){point ans = u1;double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));ans.x += (u2.x - u1.x)*t;ans.y += (u2.y - u1.y)*t;return ans;}void change_wise(point p[],int n){for(int i=0; i<n/2; i++)swap(p[i],p[n-i-1]);}void inst_hp(point p[],int n,point s[],int &len){point tp[MAX];p[n] = p[0];for(int i=0; i<=n; i++)tp[i] = p[i];int cp = n,tc;for(int i=0; i<n; i++){tc = 0;for(int k=0; k<cp; k++){if( xyd(crossProduct(p[i],p[i+1],tp[k]),0.0) )// 顺时针的话是dyd s[tc++] = tp[k];if( xy(crossProduct(p[i],p[i+1],tp[k])* crossProduct(p[i],p[i+1],tp[k+1]),0.0) )s[tc++] = l2l_inst_p(p[i],p[i+1],tp[k],tp[k+1]);}s[tc] = s[0];for(int k=0; k<=tc; k++)tp[k] = s[k];cp = tc;}len = cp;}double area_polygon(point p[],int n){double s = 0.0;for(int i=0; i<n; i++)s += p[(i+1)%n].y * p[i].x - p[(i+1)%n].x * p[i].y;return s/2.0;}int main(){int len,ncases,n;scanf("%d",&ncases);while( ncases-- ){scanf("%d",&n);for(int i=0; i<n; i++)scanf("%lf%lf",&p[i].x,&p[i].y);double area = area_polygon(p,n);if( xyd(area,0.0) ) change_wise(p,n);inst_hp(p,n,s,len);double ans = area_polygon(s,len);printf("%.2lf\n",fabs(ans));}return 0;


 

 

原创粉丝点击