uva 221

题目链接

因为输入的横坐标为小数,所以无法通过遍历横坐标来确定某一个建筑物是否可见

因为坐标是无穷的

考虑使用离散化(化无穷为有限) 

解决方案是将所有x坐标排序并去重,所有两个相邻的x坐标之间的任何位置具有相同的属性

所以可以任取两个x坐标之间的数,来代表这个区间

判断建筑i是否可见,先判断它在哪个区间,然后判断是否被遮挡

#include
#include
using namespace std;
#define N 100+5

struct Building
{
	double x, y, w, d, h;
	int id;
	bool operator< (const Building& b) const {
		return x < b.x || (x == b.x&&y < b.y);
	}
};
Building b[N];
int n;
double x[2 * N];
bool cover(int k,double mx)
{
	return b[k].x <= mx && (b[k].x + b[k].w) >= mx;
}
bool visible(int k,double mx)
{
	if (!cover(k, mx)) return 0;
	for (int i = 0; i < n; i++)
		if (b[i].y < b[k].y&&b[i].h >= b[k].h&&cover(i, mx)) return false;
	return true;
}
int main()
{
	for (int kcase = 1; cin >> n; kcase++) {
		if (n == 0) break;
		for (int i = 0; i < n; i++) {
			cin >> b[i].x >> b[i].y >> b[i].w >> b[i].d >> b[i].h;
			x[2 * i] = b[i].x; x[2 * i + 1] = b[i].x + b[i].w;
			b[i].id = i + 1;
		}
		sort(b, b + n);
		sort(x, x + 2 * n);
		int cnt = unique(x, x + 2 * n) - x;  //去除区间中相同元素,返回去重后的尾地址
		if (kcase > 1) puts("");
		printf("For map #%d, the visible buildings are numbered as follows:\n%d", kcase, b[0].id);
		for (int i = 1; i < n; i++) {
			bool vis = false;
			for (int j = 0; j < cnt - 1; j++)
				if (visible(i, (x[j] + x[j + 1]) / 2)) { vis = true; break; }
			if (vis) cout << ' ' << b[i].id;
		}
		puts("");
	}
}
/*
14
160 0 30 60 30
125 0 32 28 60
95 0 27 28 40
70 35 19 55 90
0 0 60 35 80
0 40 29 20 60
35 40 25 45 80
0 67 25 20 50
0 92 90 20 80
95 38 55 12 50
95 60 60 13 30
95 80 45 25 50
165 65 15 15 25
165 85 10 15 35
*/

你可能感兴趣的:(uva 221)