城市正视图 Urban Elevations(UVa221)

// 题目 https://www.luogu.com.cn/problem/UVA221

/*
*	以左下角作为坐标原点
*	分析:
*		思路:将坐标离散化,化无穷为有穷
*		方法:将x轴分割为有限个区间(根据建筑物的坐标和宽度),
*		对于每一个建筑物判断其是否在某一段能露出来
*		判断方法:由于每个建筑物高度是水平的(即高度不变),因此只需在该区间上任取一点(取中点简单)
*		然后判断是否比他前面的建筑物高,只要该建筑物在某一区间能露出来就输出。
*/
#define _CRT_SECURE_NO_WARNINGS
#define LOCAL 1
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 100 + 5;
struct Building {
	int id;
	double x, y, w, d, h;
	bool operator <(const Building& build) {
		return x < build.x || (x == build.x && y < build.y);
	}
}b[maxn];

int n; // n个建筑物
double x[maxn * 2]; //存放各个区间段
bool cover(int i, double mx) {
	return b[i].x <= mx && (b[i].x + b[i].w) >= mx;
}
bool isvisible(int i, double mx) {
	if (!cover(i, mx)) return false; //建筑物i不在该区段
	for (int j = 0; j < n; j++) {
		if(cover(j, mx)&&b[j].y<b[i].y&&b[j].h>=b[i].h)return false; //建筑物被挡住
	}
	return true;
}
int main()
{
#ifdef LOCAL
	freopen("C:/Users/pyliu/代码/Visual stdio/语言篇/STL入门/竞赛题目/城市正视图 Urban Elevations/input.txt", "r", stdin);
#endif // LOCAL
	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[2 * i] = b[i].x; 
			x[2 * i + 1] = b[i].x + b[i].w;
			b[i].id = i + 1;
		}
		sort(b, b + n); // x坐标小的在前,x相同y值小的在前
		sort(x, x + 2 * n);
		// unique方法(将相邻重复元素放到数组后面)去除相邻重复元素,最后 m的值为去重后元素的个数
		int m = unique(x, x + 2 * n) - x;
		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++) { //对剩下n-个建筑物判断
			bool vis = false;
			for (int j = 0; j < m - 1; j++) {
				if (isvisible(i, (x[j] + x[j + 1]) / 2)) { vis = true; break; }
			}
			if (vis) printf(" %d", b[i].id);
		}
		printf("\n");
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值