【BZOJ】4445: [Scoi2015]小凸想跑步 半平面交/线性规划

版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82711019

传送门:bzoj4445


题解

半平面交模板+学习笔记 _zwl

n 10 5 ,可以枚举除 0 1 边之外凸包上的所有边与 01 边列一个方程,解出式子 a x + b y + c = 0 a , b , c 的值,使得 a x + b y + c > 0 a x + b y + c < 0 ,这样可以列出 n 1 个不等式来限制答案坐标 ( x , y ) ,加上之前凸包边的限制。半平面交圈出来的区域就是可行的面积。

详细讲一下如何列方程(??):

设向量之间的叉积运算符号为 ,按逆时针顺序给定凸包上的点 a i ( x i , y i ) ,图中存在点 P ( x , y ) ,使得 S Δ a 0 a 1 P S Δ a i a i + 1 P ( 1 i < n ) ,设 a n = a 0

v i = ( x i , y i ) = ( x i x , y i y )

考虑 S Δ a i a i + 1 P 可以用叉积表示: S Δ a i a i + 1 P = v i v i + 1 2

上面的要求就可以转化为:

v 0 v 1 v i v i + 1 ( 1 i < n )

展开 v i v i + 1 = x i y i + 1 x i + 1 y i 得到:

扫描二维码关注公众号,回复: 3359867 查看本文章

v 0 v 1 + ( y 0 y 1 ) x + ( x 1 x 0 ) y v i v i + 1 + ( y i y i + 1 ) x + ( x i + 1 x i ) y

最终得到不等式:

( y 0 y 1 y i + y i + 1 ) x + ( x 0 + x 1 + x i x i + 1 ) y + v 0 v 1 v i v i + 1 0

记得构造直线时判断方向和特判 a , b 为0的情况。要耐心推式子&判断。


代码

#include<bits/stdc++.h>
#define RI register
#define db double
#define eps 1e-10
using namespace std;
const int N=1e5+100;

int n,tot,hd,tl,Q[N<<1];
db pre,nw,whle,area;

struct P{
    db x,y;
    P(){};
    P(db _x_,db _y_){x=_x_;y=_y_;}
}p[N],t[N<<1];

inline db fab(db x){if(x>-eps && x<eps) return 0;return x<eps?(-x):x;}
inline int dcmp(db x){if(x>-eps && x<eps) return 0;return x<eps?(-1):1;}

P operator +(const P&A,const P&B){return P(A.x+B.x,A.y+B.y);}
P operator -(const P&A,const P&B){return P(A.x-B.x,A.y-B.y);}
db operator ^(const P&A,const P&B){return A.x*B.y-A.y*B.x;}
P operator *(const P&A,const db&B){return P(A.x*B,A.y*B);}
P operator /(const P&A,const db&B){return P(A.x/B,A.y/B);}

struct L{
    P st,dir;db ang;
    L(){};
    L(P _st_,P _ed_){st=_st_;dir=_ed_-_st_;ang=atan2(dir.y,dir.x);}
}le[N<<1];

inline bool cmp(const L&A,const L&B){return A.ang<B.ang;}
inline bool onlf(const L&A,const P&B){return dcmp(A.dir^(B-A.st))==1;}
inline P insp(L A,L B)
{
    db aa=A.dir^B.dir,bb=B.dir^(A.st-B.st);
    return A.st+A.dir*bb/aa;
}

int main(){
    RI int i,j,nx,ny;db px,py;P des;
    scanf("%d",&n);
    scanf("%lf%lf",&p[1].x,&p[1].y);
    for(i=2;i<=n;++i){
        scanf("%lf%lf",&p[i].x,&p[i].y);
        le[++tot]=L(p[i-1],p[i]);
    }
    le[++tot]=L(p[n],p[1]);p[n+1]=p[1];
    for(i=1;i<=n;++i) whle+=p[i]^p[i+1];
    pre=p[1]^p[2];
    for(i=2;i<=n;++i){
        px=p[1].y-p[2].y-p[i].y+p[i+1].y;
        py=p[1].x-p[2].x-p[i].x+p[i+1].x;
        nx=dcmp(px);ny=dcmp(py);
        if(!nx && !ny) continue;
        tot++;nw=p[i]^p[i+1];
        //一些特判
        if(!nx){
            if(ny==-1) le[tot]=L(P(1.0,(pre-nw)/py),P(0.0,(pre-nw)/py));
            else le[tot]=L(P(0.0,(pre-nw)/py),P(1.0,(pre-nw)/py));
        }else if(!ny){
            if(nx==-1) le[tot]=L(P((nw-pre)/px,1.0),P((nw-pre)/px,0.0));
            else le[tot]=L(P((nw-pre)/px,0.0),P((nw-pre)/px,1.0));
        }else{
            if(ny==-1) le[tot]=L(P(1.0,(px+pre-nw)/py),P(0.0,(pre-nw)/py));
            else le[tot]=L(P(0.0,(pre-nw)/py),P(1.0,(px+pre-nw)/py));
        }
    }
    //半平面交
    sort(le+1,le+tot+1,cmp);
    hd=tl=1;Q[1]=1;
    for(i=2;i<=tot;++i){
       for(;hd<tl && (!onlf(le[i],t[tl-1]));--tl);
       for(;hd<tl && (!onlf(le[i],t[hd]));++hd);
       Q[++tl]=i;
       if(dcmp(le[Q[tl]].dir^le[Q[tl-1]].dir)==0){
          tl--;
          if(onlf(le[Q[tl]],le[i].st)) Q[tl]=i;
       }
       if(hd<tl) t[tl-1]=insp(le[Q[tl]],le[Q[tl-1]]);
    }
    for(;hd<tl && (!onlf(le[Q[hd]],t[tl-1]));--tl);
    if(hd+1>=tl) {puts("0.0000");return 0;}
    t[tl]=insp(le[Q[hd]],le[Q[tl]]);
    t[tl+1]=t[hd];
    for(i=hd;i<=tl;++i) area+=t[i]^t[i+1];
    printf("%.4lf\n",fab(area*0.5)/fab(whle*0.5));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/82711019