城市正视图,紫书P132UVa221

来源:互联网 发布:http默认端口号 编辑:程序博客网 时间:2024/06/07 10:00

不亏是ACM世界总决赛题目,不涉及任何数据结构,还能如此的复杂。正视图我们人类看是十分简单,但是要是交给及其判断真是十分的复杂。本题最大的难点是所有楼的坐标是用实数表示的,否则就可以用以为线性数组按楼每个楼在坐标轴上的覆盖区间对比高度刷新一维数组即可。但是正因为是实数,所以根本无法实现。
本题的解题核心关键是,虽然楼与楼彼此之间覆盖的情况多种多样,但是楼的边缘(包括左右两边)x轴的坐标与其水平距离最近的边缘(可能是自己的另一边也可能是其他楼的侧边,根据楼与楼彼此重叠的情况而定)的x轴的坐标所构成的区间,是整个正视图水平线上的最小区间。因为已经是最小区间了,所以其他的楼要么完全覆盖这个区间,要么完全不覆盖这种区间。那么当个楼完全覆盖某个最小区间并且它比他前面覆盖了这个最小区间的楼还要高,那么他在正视图中就能看见。
算法核心:
1.判断某个楼在某个最小区间上是否可见。

bool visible(int i, double mx) {  if(!cover(i, mx)) return false;  for(int k = 0; k < n; k++)    if(b[k].y < b[i].y && b[k].h >= b[i].h && cover(k, mx)) return false;  return true;}

因为区间已经是不可分割的了,所以判断判断某个楼是否覆盖在某个最小区间上,只要在区间上取一点即可。刘取的是中点。

2.判断所以判断判断某个楼是否覆盖在某个最小区间上。

bool cover(int i, double mx) {  return b[i].x <= mx && b[i].x+b[i].w >= mx;}

语法要点:
1.使用了自定义数据类型building,并且重载了小于运算符,使得楼与楼之间的顺序比较更加简洁。

// UVa221 Urban Elevations// Rujia Liu#include<cstdio>#include<algorithm>using namespace std;const int maxn = 100 + 5;struct Building {  int id;  double x, y, w, d, h;  bool operator < (const Building& rhs) const {    return x < rhs.x || (x == rhs.x && y < rhs.y);  }} b[maxn];int n;double x[maxn*2];bool cover(int i, double mx) {  return b[i].x <= mx && b[i].x+b[i].w >= mx;}// 判断建筑物i在x=mx处是否可见bool visible(int i, double mx) {  if(!cover(i, mx)) return false;  for(int k = 0; k < n; k++)    if(b[k].y < b[i].y && b[k].h >= b[i].h && cover(k, mx)) return false;  return true;}int main() {  int kase = 0;  while(scanf("%d", &n) == 1 && n) {    for(int i = 0; i < n; i++) {      scanf("%lf%lf%lf%lf%lf", &b[i].x, &b[i].y, &b[i].w, &b[i].d, &b[i].h);      x[i*2] = b[i].x; x[i*2+1] = b[i].x + b[i].w;      b[i].id = i+1;    }    sort(b, b+n);    sort(x, x+n*2);    int m = unique(x, x+n*2) - x; // x坐标排序后去重,得到m个坐标     if(kase++) printf("\n");    printf("For map #%d, the visible buildings are numbered as follows:\n%d", kase, b[0].id);    for(int i = 1; i < n; i++) {      bool vis = false;      for(int j = 0; j < m-1; j++)        if(visible(i, (x[j] + x[j+1]) / 2)) { vis = true; break; }      if(vis) printf(" %d", b[i].id);    }    printf("\n");  }  return 0;}