1 条题解

  • 0
    @ 2025-5-12 18:04:09

    解题思路

    问题分析

    房屋和房产边界是两条平行于xx轴的线段,房屋在上方。障碍物也是平行于xx轴的线段。

    我们需要找到房产边界上的所有点 xx,使得从 (xx, propertypropertyyy) 到房屋的左右端点 (househousex1x1, househouseyy) 和 (househousex2x2, househouse_yy) 的连线不被任何障碍物遮挡。

    遮挡的判断:对于房产边界上的点 xx,如果存在障碍物与连接 (xx, propertyproperty_yy) 和房屋的某一点的连线相交,则该点 xx 会被遮挡。

    几何方法

    对于房产边界上的点 xx,可以“看到”房屋的完整条件是:从 (xx, propertyproperty_yy) 到房屋的左右端点的连线不与任何障碍物相交。

    具体来说,对于房屋的左端点 (hx1hx1, hyhy) 和右端点 (hx2hx2, hyhy),障碍物 (ox1ox1, ox2ox2, oyoy) 会遮挡房产边界上的某些区间:

    从 (xx, propertyproperty_yy) 到 (hx1hx1, hyhy) 的连线与障碍物的遮挡区间:xx 的取值范围可以通过几何相似三角形计算。

    类似地,从 (xx, propertyproperty_yy) 到 (hx2hx2, hyhy) 的连线与障碍物的遮挡区间。

    障碍物会遮挡房产边界上的一个区间,我们需要将所有障碍物的遮挡区间合并,然后找到未被遮挡的最大区间。

    算法选择

    对于每个障碍物,计算其在房产边界上的遮挡区间(即不能看到房屋的区间)。

    将所有遮挡区间合并,得到总遮挡区间。

    房产边界上的可见区间是总遮挡区间的补集,然后找到最长的连续可见区间。

    解题方法

    遮挡区间计算

    对于障碍物 (ox1ox1, ox2ox2, oyoy),计算从房屋的左端点 (hx1hx1, hyhy) 和右端点 (hx2hx2, hyhy) 到房产边界 (xx, pypy) 的连线是否与障碍物相交。

    遮挡区间是房产边界上所有 xx 使得从 (xx, pypy) 到 (hx1hx1, hyhy) 或 (hx2hx2, hyhy) 的连线穿过障碍物。

    具体计算

    从 (xx, pypy) 到 (hx1hx1, hyhy) 的直线方程为:(yy - pypy) / (hyhy - pypy) = (xx' - xx) / (hx1hx1 - xx)。

    障碍物的 yy = oyoy,代入得到 xx' = xx + (oyoy - pypy) / (hyhy - pypy) * (hx1hx1 - xx)。

    如果 xx' 在 [ox1ox1, ox2ox2] 内,则 xx 被遮挡。

    解不等式 ox1ox1 <= xx + kk * (hx1hx1 - xx) <= ox2ox2,其中 kk = (oyoy - pypy) / (hyhy - pypy)。

    类似地计算右端点 hx2 的遮挡区间。

    合并区间

    将所有障碍物的遮挡区间合并,得到总遮挡区间。

    房产边界的可见区间是 [px1px1, px2px2] 减去总遮挡区间。

    在剩余区间中找到最长的连续区间。

    C++代码实现:

    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <iomanip>
    #include <vector>
    using namespace std;
    
    const double EPS=1e-8;
    const int MAXN=200;
    
    int dblcmp(double x){
        return fabs(x)<EPS?0:(x>0?1:-1);
    }
    
    struct Point;
    typedef Point Vector;
    
    struct Point{
        double x,y;
        Point(){}
        Point(double _x,double _y):x(_x),y(_y){}
        Vector operator -(Point p){
            return Vector(x-p.x,y-p.y);
        }
        double operator ^(Vector v){ //叉积
            return x*v.y-y*v.x;
        }
    };
    
    struct Region{ //遮挡区域
        double lx,rx;
        Region(){}
        Region(double _lx,double _rx):lx(_lx),rx(_rx){}
    };
    
    struct Line{
        Point p1,p2;
        Line(){}
        Line(Point _p1,Point _p2):p1(_p1),p2(_p2){}
        bool input(){
            double x1,x2,y;
            cin>>x1>>x2>>y;
            if(x1==0&&x2==0&&y==0) return false;
            p1=Point(x1,y); p2=Point(x2,y);
            return true;
        }
        double intersectionPointX(Line l){ //定点分比法求交点(x坐标)
            double s1=(l.p1-p1)^(p2-p1);
            double s2=(l.p2-p1)^(p2-p1);
            return (s2*l.p1.x-s1*l.p2.x)/(s2-s1);
        }
        double length(){
            return p2.x-p1.x;
        }
    };
    
    
    Line house,property;
    vector<Line> obstacles;
    vector<Region> regions;
    
    bool compare(const Region& r1,const Region& r2){
        return r1.lx<r2.lx;
    }
    
    void solve(){
        int m=obstacles.size();
        if(!m){
            cout<<fixed<<setprecision(2)<<property.length()<<endl;
            return ;
        }
        regions.clear();
        for(int i=0;i<m;++i){ //求每个障碍线的遮挡区域
            Point left=obstacles[i].p1;
            Point right=obstacles[i].p2;
            double x1=property.intersectionPointX(Line(left,house.p2)); //左端点
            double x2=property.intersectionPointX(Line(right,house.p1)); //右端点
            regions.push_back(Region(max(property.p1.x,x1),min(property.p2.x,x2)));
        }
        sort(regions.begin(),regions.end(),compare); //排序,方便后面合并相连的遮挡区域
        vector<Region> r;
        Region region=Region(regions[0].lx,regions[0].rx);
        for(int i=1;i<m;++i){ //合并相连的遮挡区域
            if(region.rx>regions[i].lx-EPS)
                region.rx=max(region.rx,regions[i].rx);
            else{
                if(region.rx>region.lx) //一开始没有判断这个,wa了好久。。
                    r.push_back(region);
                region=Region(regions[i].lx,regions[i].rx);
            }
        }
        if(region.rx>region.lx)
            r.push_back(region);
        m=r.size();
        double ans=r[0].lx-property.p1.x;
        for(int i=0;i<m-1;++i){
            ans=max(ans,r[i+1].lx-r[i].rx);
        }
        ans=max(ans,property.p2.x-r[m-1].rx);
        if(ans<EPS) cout<<"No View"<<endl;
        else cout<<fixed<<setprecision(2)<<ans<<endl;
    }
    
    int main(){
        while(house.input()){
            property.input();
            int n;
            cin>>n;
            Line obstacle;
            obstacles.clear();
            for(int i=0;i<n;++i){
                obstacle.input();
                if(obstacle.p1.y>house.p1.y-EPS||obstacle.p1.y<property.p1.y+EPS)
                    continue; //排除不在房屋和观光线之间的
                obstacles.push_back(obstacle);
            }
            solve();
        }
        return 0;
    }
    • 1

    信息

    ID
    1075
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者