题目描述: 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>