POJ - 2074 Line of Sight 射线遮盖

An architect is very proud of his new home and wants to be sure it can be seen by people passing by his property line along the street. The property contains various trees, shrubs, hedges, and other obstructions that may block the view. For the purpose of this problem, model the house, property line, and obstructions as straight lines parallel to the x axis: 

To satisfy the architect's need to know how visible the house is, you must write a program that accepts as input the locations of the house, property line, and surrounding obstructions and calculates the longest continuous portion of the property line from which the entire house can be seen, with no part blocked by any obstruction.
Input
Because each object is a line, it is represented in the input file with a left and right x coordinate followed by a single y coordinate:
< x1 > < x2 > < y > 
Where x1, x2, and y are non-negative real numbers. x1 < x2 
An input file can describe the architecture and landscape of multiple houses. For each house, the first line will have the coordinates of the house. The second line will contain the coordinates of the property line. The third line will have a single integer that represents the number of obstructions, and the following lines will have the coordinates of the obstructions, one per line. 
Following the final house, a line "0 0 0" will end the file. 
For each house, the house will be above the property line (house y > property line y). No obstruction will overlap with the house or property line, e.g. if obstacle y = house y, you are guaranteed the entire range obstacle[x1, x2] does not intersect with house[x1, x2].
Output

For each house, your program should print a line containing the length of the longest continuous segment of the property line from which the entire house can be to a precision of 2 decimal places. If there is no section of the property line where the entire house can be seen, print "No View".



这里有一个物理知识点。我们站在C处看A,在A和C之间如果存在障碍物B。 那么视觉盲点就A的左端点与B的右端点构成的直线在C上形成一个交点。同样,A的右端点与B的左端点构成的直线在C上形成一个交点。两个交点之间的就是视觉盲点。

我们枚举所有的障碍物,求得所有的视觉盲点的直线。之后按左端点排序。从规定的马路区间内找最大的间隔即可。



核心代码

//通过一条直线的两个点,计算在某一个y坐标时的坐标
point pointGetFromLine(line &l,double y){
if( isZero(l.a.y - l.b.y) ){
if(isZero(l.a.y - y))
return point(0.0,y);
return point(0.0,0.0);
}else if(isZero(l.a.x - l.b.x)){
return point(l.a.x,y);
}else{
double ret = l.a.x - (l.a.y - y)*(l.b.x-l.a.x)/(l.b.y - l.a.y);
return point(ret,y);
}
}






#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;


const double eps = 1e-8;
const int MAXN = 1111;
double hx1,hx2,hy;  // house
double fx1,fx2,hf;  // property line
int n;
bool isZero(double a){
if(fabs(a) < eps)
return true;
else return false;

struct point  
{  
    double x,y;  
point(){}
point(double _x,double _y){ x=_x,y=_y;}
};  
struct line  
{  
    point a,b;  
line(){}
line(point _a,point _b){a = _a,b=_b;}
}L[MAXN];
//通过一条直线的两个点,计算在某一个y坐标时的坐标
point pointGetFromLine(line &l,double y){
if( isZero(l.a.y - l.b.y) ){
if(isZero(l.a.y - y))
return point(0.0,y);
return point(0.0,0.0);
}else if(isZero(l.a.x - l.b.x)){
return point(l.a.x,y);
}else{
double ret = l.a.x - (l.a.y - y)*(l.b.x-l.a.x)/(l.b.y - l.a.y);
return point(ret,y);
}
}
struct inFireLine{
point p1;
point p2;
inFireLine(){}
inFireLine(point _p1,point _p2){
p1=_p1;  p2=_p2;
}
}inFire[MAXN<<1];
//bool cmp(int i,int j){
// return inFire[i].p.x < inFire[j].p.x || ( inFire[i].p.x == inFire[j].p.x && !is_right);
//}
bool cmp(const inFireLine &f1, const inFireLine &f2){
return f1.p1.x < f2.p1.x || ( f1.p1.x == f2.p1.x && f1.p2.x < f2.p2.x);
}
int firCur;
void solve(){
point p_house_left = point(hx1,hy),p_house_right = point(hx2,hy);
firCur = 0;
for(int i = 0;i < n;i++){
if(L[i].a.y + eps > hy || L[i].a.y + eps < hf || isZero(hy - L[i].a.y) || isZero(hf - L[i].a.y) ) //不在中间的障碍物直接抛弃
continue;
//房子的右点 跟遮挡物的左点 ,y
line l1 = line(p_house_right,L[i].a);
point t1 = pointGetFromLine( l1, hf);
t1.x = max(1.0*fx1,t1.x);
line l2 = line(p_house_left,L[i].b);
//房子的左点 跟遮挡物的左点 ,y
point t2 = pointGetFromLine( l2, hf);
t2.x = min(1.0*fx2,t2.x);
if(t1.x > fx2 + eps || t2.x +eps < fx1)
continue;
inFire[firCur++] = inFireLine(t1,t2);
}
sort(inFire,inFire+firCur,cmp);
double ans = 0;
double lastX = fx1,left_tot = 0; //left_tot是计算左节点的数目

if(firCur){
for(int i = 0;i < firCur;i++){
if(inFire[i].p1.x > lastX + eps){
ans = max(ans, inFire[i].p1.x - lastX);
lastX = inFire[i].p2.x;
}else if(inFire[i].p2.x > lastX + eps){
lastX = inFire[i].p2.x;
}
}
if(lastX + eps < fx2)
ans = max(ans,fx2 - lastX);
}else{
ans = fx2-fx1;
}
if(isZero(ans)){
printf("0.00\n");
}else{
printf("%.2lf\n",ans);
}
}
int main(){
while(cin >> hx1 >> hx2 >> hy){
if(isZero(hx1+hx2+hy))
break;
cin >> fx1 >> fx2 >> hf;
cin >> n;
double a,b,c;
for(int i = 0;i < n;i++){
cin >> a >> b >> c;
L[i].a = point(a,c); L[i].b = point(b,c);
}

solve();
}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值