1 条题解
-
0
解题思路
问题分析:
房屋和房产边界是两条平行于轴的线段,房屋在上方。障碍物也是平行于轴的线段。
我们需要找到房产边界上的所有点 ,使得从 (, ) 到房屋的左右端点 (, ) 和 (, _) 的连线不被任何障碍物遮挡。
遮挡的判断:对于房产边界上的点 ,如果存在障碍物与连接 (, _) 和房屋的某一点的连线相交,则该点 会被遮挡。
几何方法:
对于房产边界上的点 ,可以“看到”房屋的完整条件是:从 (, _) 到房屋的左右端点的连线不与任何障碍物相交。
具体来说,对于房屋的左端点 (, ) 和右端点 (, ),障碍物 (, , ) 会遮挡房产边界上的某些区间:
从 (, _) 到 (, ) 的连线与障碍物的遮挡区间: 的取值范围可以通过几何相似三角形计算。
类似地,从 (, _) 到 (, ) 的连线与障碍物的遮挡区间。
障碍物会遮挡房产边界上的一个区间,我们需要将所有障碍物的遮挡区间合并,然后找到未被遮挡的最大区间。
算法选择:
对于每个障碍物,计算其在房产边界上的遮挡区间(即不能看到房屋的区间)。
将所有遮挡区间合并,得到总遮挡区间。
房产边界上的可见区间是总遮挡区间的补集,然后找到最长的连续可见区间。
解题方法
遮挡区间计算:
对于障碍物 (, , ),计算从房屋的左端点 (, ) 和右端点 (, ) 到房产边界 (, ) 的连线是否与障碍物相交。
遮挡区间是房产边界上所有 使得从 (, ) 到 (, ) 或 (, ) 的连线穿过障碍物。
具体计算:
从 (, ) 到 (, ) 的直线方程为:( - ) / ( - ) = ( - ) / ( - )。
障碍物的 = ,代入得到 = + ( - ) / ( - ) * ( - )。
如果 在 [, ] 内,则 被遮挡。
解不等式 <= + * ( - ) <= ,其中 = ( - ) / ( - )。
类似地计算右端点 hx2 的遮挡区间。
合并区间:
将所有障碍物的遮挡区间合并,得到总遮挡区间。
房产边界的可见区间是 [, ] 减去总遮挡区间。
在剩余区间中找到最长的连续区间。
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
- 上传者