/* 这题的基本思想是坐标离散化,之前看《挑战程序设计竞赛》时,做过类似的题如下: GCJ 2008 APAC local onsites C Millionaire 链接:http://blog.csdn.net/mofushaohua_ln/article/details/77647763 说明:这题是概率题,虽然不算是坐标离散化,不过思路也是离散化,当时做这题时,因为是第一次接触离散化这个思想,所以理解的过程相当艰难...但是即使到了现在,我仍然觉得这是一道十分值得重做的概率题 坐标离散化技巧(来自挑战) blog: http://blog.csdn.net/mofushaohua_ln/article/details/77795409 说明:这是做的第二道离散化的题,有了前一道的基础和广搜的基础,所以这题理解时并不是很困难,不过用来复习离散化的思路还是不错的~ ****本题思路****(详见入门经典P132) 建筑物的可见性等价于南墙的可见性,可在输入后直接忽略“深度”参数 一个建筑物可能只有部分可见,但我们不可能枚举所有的x,来查看这个建筑在该处是否可见,因为x多穷多 解决方法:离散化,把无穷变为有限 具体方法:所有x坐标(准确说,是每个宽度范围,对应的两个上下限的x坐标),排序去重,任意两相邻的区间具有相同属性。一个区间要么完全可见,要么完全不可见。只需在这个区间里任选一点,就能判断处一个建筑物是否在整个区间内可见。 如何判断一个建筑物是否在某个坐标处可见? 首先,建筑物坐标中必须包含这个x坐标,其次,建筑物南边不能有另外一个不比它矮的建筑物也包含这个x坐标 */
#include <iostream> #include <algorithm> using namespace std; const int maxn = 105; int n; double x[maxn * 2]; //记录每个建筑物的宽度范围的上下限 struct Building { int id; double x, y, w, d, h; bool operator < (const Building &a) const { return x < a.x || (x == a.x && y < a.y); } }b[maxn]; istream& operator >> (istream &in, Building &a) { in >> a.x >> a.y >> a.w >> a.d >> a.h; return in; } 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() { cin.tie(0); cin.sync_with_stdio(false); int kase = 0; while (cin >> n && n) { for (int i = 0; i < n; i++) { cin >> b[i]; 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 + 2 * n); int m = unique(x, x + n * 2) - x; //去重后,得到m个坐标 if (kase++) cout << endl; cout << "For map #" << kase << ", the visible buildings are numbered as follows:" << endl << 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) cout << " " << b[i].id; } cout << endl; } return 0; }