1

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue> 
#include<ctype.h>
//#include<bits/stdc++.h>

using namespace std;

typedef double db;
const db eps=1e-8;
const db PI=acos(-1.0); 
const int maxn=3e5+10;
int n;


inline db readb()
{   
    int f=1;db x=0;char s=getchar();
    for( ;!isdigit(s);s=='-' && (f=-1),s=getchar());
    for( ;isdigit(s);x=x*10+s-48,s=getchar());
    if( s=='.' ) for( db l=0.1,s=getchar();isdigit(s);x=x+(s-48)*l,l/=10,s=getchar() );
    return x*f;
}

int sgn( double d ) { return (d>eps)-(d<-eps); }; // 精度判断 


struct point{
    db x,y;
    point(){ x=y=0; }
    point(db _x,db _y ){ x=_x,y=_y; }
    point operator + ( const point &rhs ) const { return point(x+rhs.x,y+rhs.y); }
    point operator - ( const point &rhs ) const { return point(x-rhs.x,y-rhs.y); }
    point operator / ( const int &rhs ) const { return point(x/rhs,y/rhs); }
    db operator * ( const point &rhs ) const { return 1ll*x*rhs.y-1ll*y*rhs.x; } 
    point operator * ( const db &rhs ) const { return point(x*rhs,y*rhs);}
    db dot( const point &rhs ) const { return 1ll*x*rhs.x+1ll*y*rhs.y; }
    void get(){ x=readb(),y=readb(); }
    bool operator == ( const point &rhs ) const { return x==rhs.x && y==rhs.y; }
    bool operator < ( const point &rhs ) const { return sgn(x-rhs.x)<0 || sgn(x-rhs.x)==0 && sgn(y-rhs.y)<0 ; }
    point Rotate( db rad ) { return point(x*cos(rad)-y*sin(rad), x*sin(rad)+y*cos(rad) ); }
    db  sdis() { return sqrt(x*x+y*y); }
    // bool operator < ( const point &rhs ) const { return (*this)*rhs>0 ; } 极角排序 
};

 db dist( point a,point b ) { return sqrt( (b-a).dot(b-a) ); }

bool getdir( point p[],int n ) // true  逆时针存边   
{
    db ans=0;
    for( int i=0;i<n;i++ ) ans+=p[i]*p[(i+1)%n];
    return sgn(ans)>0;
}


struct segment{ // 线段 
    point s,e;
    segment(){}
    segment( point _s,point _e ) { s=_s,e=_e; }
    void get( point _s,point _e ) { s=_s,e=_e; }

    bool inter(  const segment &l1, const segment &l2 ) // 两线段是否交  1 交 / 0 不交 
    {
        return     
        max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&     
        max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&     
        max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&     
        max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&     
        sgn( (l2.s-l1.e)*(l1.s-l1.e) )*sgn( (l2.e-l1.e)*(l1.s-l1.e) ) <= 0 &&     
        sgn( (l1.s-l2.e)*(l2.s-l2.e) )*sgn( (l1.e-l2.e)*(l2.s-l2.e) ) <= 0;
    } 

    bool inter1( const segment &l1,const segment &l2 ) // 两线段是否正规相交  1 交 / 0 不交 
    {
        if( inter(l1,l2) )
        {
            if( l1.s==l2.s && l1.e==l2.e || l1.s==l2.e && l1.e==l2.s ) return true;  //重合 
            else if( l1.s==l2.s || l1.s==l2.e || l1.e==l2.s || l1.e==l2.e ) return false; // 端点相交 
            return true; 
        }
        return false;
    }

    bool OnSeg( const point &p ) //判断点在线段上 1 在/ 0 不在 
    {
        return sgn( (s-p)*(e-p) )==0 
        && sgn( (p.x-s.x)*(p.x-e.x) )<=0    
        && sgn( (p.y-s.y)*(p.y-e.y) )<=0;
    }

    pair<point,int> operator & ( const segment &rhs ) const{ // 两直线相交问题 
        point res=s; //交点 
        if( sgn( (s-e)*(rhs.s-rhs.e) )==0 )
        {
            if( sgn( (rhs.s-s)*(rhs.e-s) )==0 ) return make_pair(res,0); // 两直线重合
            else return make_pair( res,1 ); // 两直线平行 
        }
        db t= ( (s-rhs.s)*(rhs.s-rhs.e) )/ ( (s-e)*(rhs.s-rhs.e) ) ; //单位化 
        res.x+=(e.x-s.x)*t;
        res.y+=(e.y-s.y)*t;
        return make_pair(res,2); // 有交点 
    }

    point NearestPointToLineSeg( const point &P,const segment &L ) // 线段 最近点对 
    {
        point result;
        db t = ( (P-L.s).dot(L.e-L.s) )/( (L.e-L.s).dot(L.e-L.s) );
        if( t >= 0 && t <= 1 )
        {
            result.x = L.s.x + (L.e.x - L.s.x)*t;
            result.y = L.s.y + (L.e.y - L.s.y)*t;
        }
        else
        {
            if(dist(P,L.s) < dist(P,L.e))
                result = L.s;
            else result = L.e;
        }
        return result;
    }



};


//--------------------直线---------------- 
struct sLine{ // 直线 
    point s,e;
    sLine(){}
    sLine( point _s,point _e ) { s=_s,e=_e; }
    sLine operator * ( const db &rhs ) const { return sLine(s*rhs,e*rhs); } 



    pair<point,int> operator & ( const sLine &rhs ) const{ // 两直线相交问题 
        point res=s; //交点 
        if( sgn( (s-e)*(rhs.s-rhs.e) )==0 )
        {
            if( sgn( (rhs.s-s)*(rhs.e-s) )==0 ) return make_pair(res,0); // 两直线重合
            else return make_pair( res,1 ); // 两直线平行 
        }
        db t= ( (s-rhs.s)*(rhs.s-rhs.e) )/ ( (s-e)*(rhs.s-rhs.e) ) ; //单位化 
        res.x+=(e.x-s.x)*t;
        res.y+=(e.y-s.y)*t;
        return make_pair(res,2); // 有交点 
    }

    int segLineCross( const sLine &s1,const segment &s2 ) // 直线和线段相交 
    {
        point a=s1.s,b=s1.e,c=s2.s,d=s2.e;
        int d1,d2;
        d1 = sgn( (b-a)*(c-a) );
        d2 = sgn( (b-a)*(d-a) );
        if( (d1^d2)==-2 ) return 1;  // 标准相交 
        if( d1==0 || d2==0 ) return 2; // 不标准相交 
        return 0; // 不相交 
    }

    db getDistance( point A ) //点到直线的距离
    { 
        return fabs((A-s)*(A-e)/dist(s,e) );
    }


    sLine Circle_inter( point o,sLine X ,db R )  //圆与直线交点
    { 
        point o2 = o;
        o2.x += X.s.y - X.e.y;
        o2.y += X.e.x - X.s.x;
        o2 = (sLine(o,o2)&X).first;
        db t = sqrt(R * R - (o2 - o).sdis() * (o2 - o).sdis()) / (X.s - X.e).sdis();
        point p1 = o2 - (X.e - X.s) * t;
        point p2 = o2 + (X.e - X.s) * t;
        return sLine(p1,p2);
    }

};


//bool Is_covbag( point p[] ,int n )
//{
//    for( int i=0;i<=n;i++ )
//        if( cross(node[i],node[i+1],node[i+1],node[i+2])<0 )
//            return false;
//    return true;
//}

//------------凸包-------------------
//判断点在凸多边形内
//点形成一个凸包,而且按逆时针排序(如果是顺时针把里面的<0改为>0)
//点的编号:0~n-1
//返回值:
//-1:点在凸多边形外
//0:点在凸多边形边界上
//1:点在凸多边形内
int inConvexPoly( point a,point p[],int n )
{
    for( int i=0;i<n;i++ )
    {
        if( sgn( ( p[i]-a )*( p[(i+1)%n]-a ) )<0 ) return -1;
        else if( segment( p[i],p[(i+1)%n] ).OnSeg(a) ) return 0;
    }
    return 1;
} 

//判断点在任意多边形内---同样适用于凸包 
//射线法,poly[]的顶点数要大于等于3,点的编号0~n-1
//返回值
//-1:点在多边形外
//0:点在多边形边界上
//1:点在多边形内
int inPoly( point p, point poly[],int n )
{
    int cnt;
    segment ray,side;
    cnt=0;ray.s=p;ray.e.y=p.y;
    ray.e.x=-100000000000.0; // -inf 注意取值防止越界
    for( int i=0;i<n;i++ )
    {
        side.s=poly[i];
        side.e=poly[(i+1)%n];
        if( side.OnSeg(p) ) return 0;
        if( sgn(side.s.y-side.e.y)==0 ) continue;
        if( ray.OnSeg(side.s) )
        {
            if( sgn(side.s.y-side.e.y)>0 ) cnt++;
        }
        else if( ray.OnSeg(side.e) )
        {
            if( sgn(side.e.y-side.s.y)>0 ) cnt++;
        }
        else if( ray.inter(ray,side) ) cnt++;
    }
    if( cnt%2==1 ) return 1;
    else return -1; 
}



point st; //  左下角起始点

bool cmp( point a,point b ) // 极角排序 
{
    db tmp=(a-st)*(b-st);
    if( sgn(tmp)==0 ) return dist(st,a)<dist(st,b );
    else return sgn(tmp)>0;
}


db Graham( point P[] ,int n ) // 构造凸包  该模板不存在三点共线 
{
    db res=0;int k=1;
    for( int i=1;i<=n;i++ ) // 获得起始点 
    {
        if( sgn(P[k].y-P[i].y)>0 || sgn(P[k].y-P[i].y)==0 && sgn( P[k].x-P[i].y)>0 ) k=i;
    }
    st=P[k];
    sort(P+1,P+1+n,cmp);
    int q[maxn],top=2;
    q[1]=1;q[2]=2;
    for( int i=3;i<=n;i++ )   // 三点共线凸包问题 n^2 check 
    {
        while( top>1 && sgn( ( P[q[top]]-P[q[top-1]] )*( P[i]-P[q[top]] ) )<=0 ) top--;
        q[++top]=i;
    } 
//    for(int i=1;i<=top;++i) printf("(%d,%d)\n",P[q[i]].x,P[q[i]].y);   // P[ q[1-top] ] 凸包上的点坐标 
//    for( int i=1;i<=top;i++ ) res+=dist( P[q[i]],P[q[i%top+1]] ); //  res ----凸包的周长 
    for( int i=3;i<=top;i++ ) res+=( P[q[i]]-P[q[i-1]] )*( P[q[1]]-P[q[i-1]] )/2.0; // res -----凸包的面积 
    return fabs(res);
} // 皮克定理:S=A+B/2-1(S为多边形面积,A为多边形内部整点数,B为多边形边上的整点数) B 等于gcd(abs( xi-x(i-1) ),abs(y i-y(i-1) ) )求和 

// 求任意多边形的面积
db CalArea( point P[],int n )
{
    db res=0;
    for( int i=1;i<=n;i++ )
    {
        res+=( P[i]*P[i%n+1] )/2.0;
    }
    return fabs(res);
}



//-----------半平面交--------- 

struct halfplane:public sLine{
    db angle;
    halfplane(){}
    halfplane( sLine v ){ s=v.s;e=v.e; }
    void CalAngle() { angle=atan2(e.y-s.y,e.x-s.x); }
    bool operator < ( const  halfplane &rhs ) const{ return angle<rhs.angle; }
};

struct polygon{ // 内核面积 
    int n;
    point p[maxn];
    db getArea()
    {
        db sum=0;
        for( int i=0;i<n;i++ ) sum+=p[i]*p[(i+1)%n];
        return fabs(sum)/2;
    }
};

struct halfplanes{
    int n; // 记得初始化 
    halfplane hp[maxn];
    point p[maxn];
    int que[maxn];int st,ed; // 双端队列
    void push( halfplane tmp ) { hp[n++]=tmp; } // sLine(p[(i+1)%n],p[i]) 顺时针存边 / sLine( p[(i-1+n)%n],p[i] ) 逆时针存边 
    // 去重
    void unique()
    {
        int m=1;
        for( int i=1;i<n;i++ )
        {
            if( sgn( hp[i].angle-hp[i-1].angle )!=0 ) hp[m++]=hp[i];
            else if( sgn( ( hp[m-1].e-hp[m-1].s )*( hp[i].s-hp[m-1].s ) )>0 ) hp[m-1]=hp[i];
        }
        n=m;
    } 

    bool halfplaneInsert() // 判断是否存在内核 ----- 存在一点到与多边形边上任意一点的连线 在多边形内部 
    {
        for( int i=0;i<n;i++ ) hp[i].CalAngle();
        sort(hp,hp+n);
        unique();
        que[st=0]=0;que[ed=1]=1;
        p[1]=( hp[0] & hp[1] ).first;
        for( int i=2;i<n;i++ )
        {
            while( st<ed && sgn( ( hp[i].e-hp[i].s )*( p[ed]-hp[i].s ) )<0 ) ed--;
            while( st<ed && sgn( ( hp[i].e-hp[i].s )*( p[st+1]-hp[i].s ) )<0 ) st++;
            que[++ed]=i;
            if( ( hp[i] & hp[ que[ed-1] ] ).second<2 ) return false;
            p[ed]=( hp[i] & hp[ que[ed-1] ] ).first; 
        }
        while( st<ed && sgn( ( hp[que[st]].e-hp[que[st]].s )*( p[ed]-hp[que[st]].s ) )<0 ) ed--;
        while( st<ed && sgn( ( hp[que[ed]].e-hp[que[ed]].s )*( p[st+1]-hp[que[ed]].s ) )<0 ) st++;
        if( st+1>=ed ) return false;
        else return true;
    }
    // 得到最后半平面交的凸多边形 点集 
    // 得到先调用halfplaneinsert(),且返回true
    void getconvex( polygon &con ) // 
    {
        p[st]=( hp[que[st]]&hp[que[ed]] ).first;
        con.n=ed-st+1;
        for( int j=st,i=0;j<=ed;j++,i++ ) con.p[i]=p[j];
    } 
}; 

void change( point p1,point p2,point &a,point &b,db p ) // 凸包边内移 p距离  ---- 可二分求 内切最大圆半径 
{
    db len=dist(p1,p2);
    db dx=(p1.y-p2.y)*p/len,dy=(p2.x-p1.x)*p/len;
    a.x=p1.x+dx;a.y=p1.y+dy;
    b.x=p2.x+dx;b.y=p2.y+dy;
}


//-------------------圆问题----------------------------
struct qnode{
    db angle;
    int in;
    bool operator < (  const qnode &rhs ) const {
        return sgn(angle-rhs.angle)<0 ||  sgn(angle-rhs.angle)==0 && in>rhs.in; 
    }
}arc[maxn];

void Min_cir_cover( point p[] ,int n ,double r ) // 最小圆覆盖 最多点 --question 求半径为 r 的圆最多能覆盖平面上多少个点
{
    int cnt=0;
    int ans=0,maxz=1;
    for( int i=1;i<=n;i++ )
    {
        ans=0,cnt=0;
        for( int j=1;j<=n;j++ )
        {
            if( dist(p[i],p[j])>2*r ) continue;
            db angle1=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
            db angle2=acos( dist(p[i],p[j])/(2*r) );
            arc[++cnt].angle=angle1-angle2;
            arc[cnt].in=1;
            arc[++cnt].angle=angle1+angle2;
            arc[cnt].in=-1;
        }
        sort(arc+1,arc+cnt+1);        
        for( int j=1;j<=cnt;j++ )
        {
            ans+=arc[j].in;
            maxz=max(maxz,ans);
        }
    }
    printf("%d\n",maxz);
}



//--------------------最短路---------------------------- 
const db inf=1e20;
#define pr pair<db,int>
struct node{
    int v;
    db len;
    int next;
}a[maxn*2];
int pre[maxn],cnt=0;
db dis[maxn];
bool vis[maxn];

void add( int u,int v,db len )
{
    a[cnt].v=v,a[cnt].len=len,a[cnt].next=pre[u];
    pre[u]=cnt++;
}

void init()
{
    memset(pre,-1,sizeof(pre)),cnt=0;
}

db dijkstra( int s ,int e ) // 起点 
{ 
    for( int i=0;i<maxn;i++ ) dis[i]=inf;
    memset( vis,0,sizeof(vis) );
    priority_queue<pr,vector<pr>,greater<pr> > q;
    q.push( make_pair(0,s) );
    dis[s]=0;
    while( !q.empty() ) 
    {
        int u=q.top().second;
        q.pop();
        vis[u]=1;
        for( int i=pre[u];~i;i=a[i].next )
        {
            int v=a[i].v;
            db len=a[i].len;
            if( !vis[v] && dis[v]>dis[u]+len )
            {
                dis[v]=dis[u]+len;
                q.push( make_pair(dis[v],v) );
            }
        }
    }
    return dis[e];
}


point p[maxn];
segment s[maxn];

int main()
{
    while( ~scanf("%d",&n) && n!=-1 )
    {
        init();
        int p_cnt=0,s_cnt=0;
        for( int i=0;i<n;i++ )
        {
            double x,y[4];
            x=readb();
            for( int j=0;j<4;j++ ) 
            {
                y[j]=readb();
            }
            for( int j=0;j<4;j++ ) p[p_cnt++]=point(x,y[j]);
            s[s_cnt++].get( point(x,0),point(x,y[0]) );
            s[s_cnt++].get( point(x,y[1]),point(x,y[2]) );
            s[s_cnt++].get( point(x,y[3]),point(x,10.0) );
        }
        p[p_cnt++]=point(10.0,5.0);
        p[p_cnt++]=point(0.0,5.0);
        for( int i=0;i<p_cnt;i++ )
        {
            for( int j=i+1;j<p_cnt;j++ )
            {
                segment tmp=segment(p[i],p[j]);
                int flag=0;
                for( int k=0;k<s_cnt;k++ )
                {
                    if( s[k].s.y==p[i].y && s[k].e.y==p[j].y && s[k].s.x==p[i].x && s[k].e.x==p[j].x )
                    {
                        flag=1;
                        break;
                    }
                    else if( s[k].s==p[i] || s[k].s==p[j] || s[k].e==p[i] || s[k].e==p[j] ) continue;

                    if( tmp.inter(tmp,s[k]) )
                    {
                        flag=1;
                        break;
                    }
                }
                if( !flag )
                {
                    add( i,j,dist(p[i],p[j]) );
                    add( j,i,dist(p[i],p[j]) );
                }
            }
        }
        db ans=dijkstra(p_cnt-2,p_cnt-1);
        printf("%.2f\n",ans);
    }
    return 0;
}
全部评论

相关推荐

只有一个苍穹外卖外加正在看黑马点评,可以找小厂实习吗,还有我的简历有什么大问题吗
Java抽象小篮子:感觉有点熟悉,问题1是学历,2是没实习经历,3是专业技能写得太少太少了(怎么写可以看我置顶帖),4是仅这一个项目找实习不够看。拷打完毕,简历怎么写可以看我置顶帖子
点赞 评论 收藏
分享
没有offer的呆呆:薪资有的时候也能说明一些问题,太少了活不活得下去是一方面,感觉学习也有限
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务