POJ 2074 Line of Sight 直线相交+线段覆盖

题目描述: http://poj.org/problem?id=2074


题目大意:

从一条路上看路一边的建筑师的家,视线可能会被其他的障碍物挡住(不考虑高度),问从这条路上能看到完整的建筑师的房子的一段路的最大长度。若整条路上都无法看见则输出“No View”, 路、房屋和障碍物都抽象成平行线段。


解题思路:

首先考虑房屋h,和路r,之间的某一条线段p。设p的左端点和h的右端点的连线与r的交点a,p的右端点和h的左端点的连线与r的交点b。容易发现当走在ab之间时视线会被挡住。对于每一条线段都可以尝试求出覆盖在r上的“盲区“ab。相当于线段覆盖,而我们只要求出不被覆盖的最大长度就好了。注意有的线段形成的盲区可能不在线段r上或者有一端不在r上,需要特殊判断。

以上考虑的是在h和r之间的线段,题目只说了障碍物不会与h和r相交,但可能在h与r之间的区域外。这种情况下障碍物不会对视线产生影响,但是用以上的方法可能计算出在r上的交点,造成WA。所以读入的时候判断一下,如果不在h与r之间直接忽视掉。

剩下的就是怎么计算最大不被覆盖的线段的问题。我们可以先把所有盲区线段以左端点坐标为关键字从小到大排序,然后从左到右扫一遍,一边维护i之前所有线段的最右端的x坐标lastX。如果第i个盲区的左端点大于lastX,那么lastX到i的左端点的这片区域都是不被覆盖的。扫描每个线段时更新lastX。r的左右端点需要特别判断一下。


复杂度:

计算盲区O(n),计算最大长度O(n)。复杂度O(n)。


<span style="font-family:Microsoft YaHei;font-size:12px;">/*
 * 	2014.11.09
 *	Problem: 2074	
 *	Memory: 192K		        Time: 0MS
 *	Language: C++		Result: Accepted
 *
 */

#include <iostream>
#include <algorithm>
#include <cmath>
#define EPS 1e-8
#define MAXN 107

using namespace std;

struct Event {
	double x1, x2;
}v[MAXN<<2];

int n, vn;
double hx1, hx2, hy, rx1, rx2, ry;

bool compare(struct Event a, struct Event b) {
	return a.x1<b.x1;
}

double getEventX(double x1, double y1, double x2, double y2) {
	return x1 - (y1-ry)*(x2-x1)/(y2-y1);
}

double max(double a, double b) {return a>b?a:b;}
double min(double a, double b) {return a>b?b:a;}

void init() {
	double v1, v2, x1, x2, y;
	vn = 0;
	scanf("%d", &n);
	for (int i=1; i<=n; i++) {
		scanf("%lf %lf %lf", &x1, &x2, &y);
		if (y >= hy || y <= ry) continue;
		v1 = getEventX(x1, y, hx2, hy);
		v2 = getEventX(x2, y, hx1, hy);
		if (v2-rx1<=EPS || v1-rx2>=-EPS) continue;
		vn++;
		v[vn].x1 = max(v1, rx1); v[vn].x2 = min(v2, rx2);
	}
}

int main() {	
	scanf("%lf %lf %lf", &hx1, &hx2, &hy);
	while (hy!=0 && hx1!=0 && hx2!=0) {
		scanf("%lf %lf %lf", &rx1, &rx2, &ry);

		init();
	
		sort(v+1, v+1+vn, compare);

		double length=0, lastX=0;;
		for (int i=1;i<=vn;i++) {
			if (v[i].x1>lastX) {
				length = max(length, v[i].x1-lastX);
				lastX  = v[i].x2;
			} else {
				lastX  = max(lastX, v[i].x2);
			}
		}
		length = max(length, rx2 - lastX);

		if (fabs(length)<EPS) {
			printf("No View\n");
		} else {
			printf("%.2lf\n", length);
		}
		
		scanf("%lf %lf %lf", &hx1, &hx2, &hy);
	}
	return 0;
}</span></span></span></span>



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值