POJ 2074 Line of Sight

题目大意:

        一座房子、一条马路,中间隔着几个障碍物,他们都可以看做线段,并且都平行于x轴,都具有一定长度,现在要求在马路上可以看到整个房子的最长的连续的一段长度。

        现有多个测例,每个测例中先给出房子左右两点的x坐标以及一个y坐标(以0 0 0作为输入的结束),接着给出马路左右两点的x坐标以及一个y坐标,接着给出一共有多上障碍物n(int型正整数),以及每个障碍物的左右端点的x坐标和一个y坐标,题中保证所有的x1、x2都有x1 < x2,并且 y房子 > y马路,障碍物位于房子和马路之间,就算和房子同样高,也不会和房子重合,其中所有的坐标输入都是实数(用double表示),对于每个测例,如果存在该最长连续线段则输出其长度(精确到小数点后两位),否则就输出“No View"。

题目链接

注释代码:

/*      
 * Problem ID : POJ 2074 Line of Sight
 * Author     : Lirx.t.Una      
 * Language   : C++     
 * Run Time   : 0 ms      
 * Run Memory : 244 KB      
*/

#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#include <cmath>

#define	EPS		1E-8

//maximum number of obstacles
//测试过的障碍物的最小数量
#define	MAXOBN	15

using namespace std;

int
sgn(double x) {//sign
	//用于判定浮点数的符号和比较两个浮点数的大小
	//sgn(a, b)   == 0相等,> 0就是a > b,< 0表示a < b
	//直接用比较符操作时CPU是比较每一位的,往往不精确
	//比如3.0有时候小数点后9、10位会是一个1、2、3之类的数字导致结果误差

	if ( fabs(x) < EPS )
		return 0;

	return x > 0 ? 1 : -1;
}

struct	Point {//点

	double	x, y;

	Point(void) {}

	Point( double xx, double yy ) :
		x(xx), y(yy) {}

	friend double//计算直线ab和与x轴平行的直线y的交点的横坐标
    //注意采用值传递
	xByY( Point a, Point b, double y ) {
	
		return ( y - a.y ) * ( a.x - b.x ) / ( a.y - b.y ) + a.x;
	}
};

struct	Line {//和x轴平行的直线

	double	x1, x2;//左右端点横坐标
	double	y;//直线的纵坐标

	Line(void) {}

	friend istream &//输入
	operator>>( istream &is, Line &l ) {
	
		is >> l.x1 >> l.x2 >> l.y;

		return is;
	}

	bool
	empty(void) {//判空,如果为空表示输入的结束

		return !sgn(x1) && !sgn(x2) && !sgn(y);
	}
};

//视线
//表示某个障碍物阻挡住整个房子的范围
//lft和rht分别表示这个阻挡范围的左右端点的横坐标
//lft为障碍物左端点和房子右端点的连线在马路上的交点的横坐标
//rht为障碍物右端点和房子左端点的连线在马路上的交点的横坐标
struct	View {

	double lft, rht;
};

bool
fcmp(const View &v1, const View &v2) {//对障碍物视线按照lft值从小到大排列

	return sgn( v1.lft - v2.lft ) <= 0;
}

Line	hs;//house,房子
Line	pl;//property line,马路
View	v[MAXOBN];//view,v[i]表示i号障碍物的遮挡范围,下标从0计

int
main() {

	int		n;//障碍物总数
	int		nb;//number of final obstacle,最终确定下来的符合“要求”的障碍物数量
	//那些在马路和房子两边的障碍物将被舍弃,即剪枝

	int		i;//计数变量
	int		rm;//right most obstacle,当前rht值最大的障碍物的序号

	double	ans;//保存最终结果,即可见范围的最大长度

	double	tmp;//临时变量
	Line	ob;//obstacle,用于临时存放输入的障碍物

	while ( cin >> hs, !hs.empty() ) {//输入房子并判空

		//由于浮点数精度问题,虽然下一个测例能完全覆盖上一个测例
		//但是还是需要清零以防止位置的精度误差
		//词句不写为蛋疼的WA的!!!
		memset(v, 0, sizeof(v));

		cin >> pl >> n;	//输入马路和障碍物总数

		//计算障碍物的遮挡范围并剔除不符合要求的障碍物
		nb = 0;
		while ( n-- ) {

			cin >> ob;
			if ( sgn( ob.y - hs.y ) >= 0 || sgn( ob.y - pl.y ) <= 0 )//剪枝1
				continue;//在房子和马路之外的范围

			//计算遮挡范围
			v[nb].lft = xByY( Point( hs.x2, hs.y ), Point( ob.x1, ob.y ), pl.y );
			v[nb].rht = xByY( Point( hs.x1, hs.y ), Point( ob.x2, ob.y ), pl.y );
			nb++;
		}
		sort(v, v + nb, fcmp);//将视线按照lft从小到大排列

		ans = 0;//处理左边界
		//0的左边界大于马路左边界,这就意味着pl.x1 ~ v[0].lft之间是可见的,可以用来初始化ans
		if ( sgn( v[0].lft - pl.x1 ) > 0 ) ans = v[0].lft - pl.x1;
		//0的右边界竟然在马路左边界左边,这就意味着0完全不能阻挡房子,因此不妨将0的右边界设为马路左边界
		if ( sgn( v[0].rht - pl.x1 ) < 0 ) v[0].rht = pl.x1;
		//其余情况就是0左边界小于马路左边界但0的右边界大于马路右边界,此种情况下0的rht仍然是当前最大的
		//因此不需做任何操作

		//rm的初始化
		//如果rm的右边界超出马路右边界就以为着后面还没被检查的障碍物的阻挡范围都被rm覆盖了
		//因为rm在前面(lft比后面的都小),因此可以直接退出循环
		for ( rm = 0, i = 1; i < nb && sgn( v[rm].rht - pl.x2 ) < 0; i++ ) {//剪枝2
	
			if ( sgn( tmp = v[i].lft - v[rm].rht ) > 0 ) {//i左边界大于rm右边界
				//这就意味着v[rm].rht ~ v[i].lft之间的范围是可见的,需要比较和ans的优劣
		
				rm = i;//i的右边界一定大于rm的rht,因此需要更新rm
				if ( sgn( tmp - ans ) > 0 )
					ans = tmp;
			}//另一种情况就是i的左边界小于rm的右边界,这就意味着有重叠
			else if ( sgn( v[i].rht - v[rm].rht ) > 0 )//但是如果i的rht大于rm的rht
				rm = i;//则当前最大的rht为i的rht,需要覆盖

			//剩余的情况是i完全被rm覆盖,因此什么都不用做,直接检测下一个障碍物
		}

		tmp = pl.x2 - v[rm].rht;//检查右边界
		if ( sgn( tmp - ans ) > 0 )
			ans = tmp;

		if ( sgn(ans) > 0 )//表示存在最长可见区
			printf("%.2lf\n", ans);
		else//ans = 0.0,不存在完全可见区
			puts("No View");
	}

	return 0;
}

无注释代码:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#include <cmath>

#define	EPS		1E-8

#define	MAXOBN	15

using namespace std;

int
sgn(double x) {

	if ( fabs(x) < EPS )
		return 0;

	return x > 0 ? 1 : -1;
}

struct	Point {

	double	x, y;

	Point(void) {}

	Point( double xx, double yy ) :
		x(xx), y(yy) {}

	friend double
	xByY( Point a, Point b, double y ) {
	
		return ( y - a.y ) * ( a.x - b.x ) / ( a.y - b.y ) + a.x;
	}
};

struct	Line {

	double	x1, x2;
	double	y;

	Line(void) {}

	friend istream &
	operator>>( istream &is, Line &l ) {
	
		is >> l.x1 >> l.x2 >> l.y;

		return is;
	}

	bool
	empty(void) {

		return !sgn(x1) && !sgn(x2) && !sgn(y);
	}
};

struct	View {

	double lft, rht;
};

bool
fcmp(const View &v1, const View &v2) {

	return sgn( v1.lft - v2.lft ) <= 0;
}

Line	hs;
Line	pl;
View	v[MAXOBN];

int
main() {

	int		n;
	int		nb;

	int		i;
	int		rm;

	double	ans;

	double	tmp;
	Line	ob;

	while ( cin >> hs, !hs.empty() ) {

		memset(v, 0, sizeof(v));

		cin >> pl >> n;	
		nb = 0;
		while ( n-- ) {

			cin >> ob;
			if ( sgn( ob.y - hs.y ) >= 0 || sgn( ob.y - pl.y ) <= 0 )
				continue;

			v[nb].lft = xByY( Point( hs.x2, hs.y ), Point( ob.x1, ob.y ), pl.y );
			v[nb].rht = xByY( Point( hs.x1, hs.y ), Point( ob.x2, ob.y ), pl.y );
			nb++;
		}
		sort(v, v + nb, fcmp);

		ans = 0;
		if ( sgn( v[0].lft - pl.x1 ) > 0 ) ans = v[0].lft - pl.x1;
		if ( sgn( v[0].rht - pl.x1 ) < 0 ) v[0].rht = pl.x1;

		for ( rm = 0, i = 1; i < nb && sgn( v[rm].rht - pl.x2 ) < 0; i++ ) {
	
			if ( sgn( tmp = v[i].lft - v[rm].rht ) > 0 ) {
		
				rm = i;
				if ( sgn( tmp - ans ) > 0 )
					ans = tmp;
			}
			else if ( sgn( v[i].rht - v[rm].rht ) > 0 )
				rm = i;
		}

		tmp = pl.x2 - v[rm].rht;
		if ( sgn( tmp - ans ) > 0 )
			ans = tmp;

		if ( sgn(ans) > 0 )
			printf("%.2lf\n", ans);
		else
			puts("No View");
	}

	return 0;
}

单词解释:

architect:n, 建筑师

sight:n, 视觉,视力,景象

property:n, 财产,所有权

shrub:n, 灌木丛

hedge:n, 树篱笆

obstruction:n, 障碍物

block:vt, 阻塞,阻碍

portion:n, 部分

landscape:n, 风景,风景画

architecture:n, 建筑学,建筑风格

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值