/*
这题的基本思想是坐标离散化,之前看《挑战程序设计竞赛》时,做过类似的题如下:
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;
}