1. 程式人生 > >bzoj 2618【半平面交模板】

bzoj 2618【半平面交模板】

有向面積 sin 刪掉 div != 半平面 UC struct per

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=505;
int d,b,n,m;
struct dian
{
    double x,y;
    dian(double X=0,double Y=0)
    {
        x=X,y=Y;
    }
    dian operator + (const dian &a) const
    {
        return
dian(x+a.x,y+a.y); } dian operator - (const dian &a) const { return dian(x-a.x,y-a.y); } dian operator * (const double &a) const { return dian(x*a,y*a); } dian operator / (const double &a) const { return dian(x/a,y/a); } }a[N],p[N]; struct
bian { dian s,v;//s表示向量的起點,v表示向量的方向和長度(從(0,0)射出) bian(dian S=dian(),dian V=dian()) { s=S,v=V; } }l[N],q[N]; double cj(dian a,dian b)//叉積 { return a.x*b.y-a.y*b.x; } double mj(dian a,dian b,dian c)//求有向面積 { return cj(b-a,c-a)/2.0; } dian jd(bian x,bian y)//求交點 { return x.s+x.v*(cj(x.s-y.s,y.v)/cj(y.v,x.v)); } bool
px(bian x,bian y)//判斷平行 { return cj(y.v,x.v)==0; } bool bn(bian x,bian y)//x在y的逆時針方向(平行先左後右 { double ar=cj(x.v,y.v); return (ar>0)||((ar==0)&&cj(x.v,y.s-x.s)>0); } bool dn(dian x,bian y)//點在線的逆時針方向 { return cj(y.v,x-y.s)<=0; } bool cmp(const bian &x,const bian &y)//極角排序 { if(x.v.y==0&&y.v.y==0)//同與x軸平行 return x.v.x<y.v.x; if((x.v.y<=0)==(y.v.y<=0))//同在x軸上或下(包括x軸) return bn(x,y); return x.v.y<y.v.y;//一上一下下在前 } int main() { scanf("%d",&d); for(int i=1;i<=d;i++) { scanf("%d",&b); for(int j=1;j<=b;j++) { int x,y; scanf("%d%d",&x,&y); p[n+j].x=x,p[n+j].y=y;//cout<<p[n+j].x<<" "<<p[n+j].y<<endl; if(j!=1) l[++m]=bian(p[n+j-1],p[n+j]-p[n+j-1]); } n+=b; l[++m]=bian(p[n],p[n-b+1]-p[n]); } //半平面交 sort(l+1,l+m+1,cmp); int top=0; for(int i=1;i<=m;i++) { if(i==1||!px(l[i],l[i-1]))//去掉平行邊 top++; l[top]=l[i]; } m=top; int ll=1,rr=2; q[1]=l[1],q[2]=l[2]; for(int i=3;i<=m;i++)//每次新加入向量,就會刪掉在向量右邊的交點(線上的也要刪),維護的凸包首尾都是要刪除的,最後還要模擬插入隊頭,把隊尾中多余的半平面去掉 { while(ll<rr&&dn(jd(q[rr],q[rr-1]),l[i])) rr--; while(ll<rr&&dn(jd(q[ll],q[ll+1]),l[i])) ll++; s[++rr]=l[i]; } while(ll<rr&&dn(jd(q[rr],q[rr-1]),q[ll])) rr--;//cout<<rr<<endl; if(rr-ll<=1) { puts("0.000"); return 0; } top=0; q[ll-1]=q[rr]; for(int i=ll;i<=rr;i++) a[++top]=jd(q[i],q[i-1]);//求出相鄰兩邊的交點,轉化為凸包的記錄方法 double ans=0.0; for(int i=3;i<=top;i++) ans+=mj(a[1],a[i-1],a[i]); printf("%.3f\n",ans); return 0; } /* 2 6 -2 0 -1 -2 1 -2 2 0 1 2 -1 2 4 0 -3 1 -1 2 2 -1 0 */

bzoj 2618【半平面交模板】