UVA

来源:互联网 发布:美国网络瘫痪 dns 编辑:程序博客网 时间:2024/05/22 16:53
/*  这题的基本思想是坐标离散化,之前看《挑战程序设计竞赛》时,做过类似的题如下:    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;}