221:Urban Elevations

Urban Elevations


书上的思路(离散化):把所有x坐标排序去重,则任意两个相邻x坐标形成的区间具有相同属性,一个区间要么完全可见,要么完全不可见。这样,只需在这个区间里任选一个点(例如中点),就能判断出一个建筑物是否在整个区间内可见。如何判断一个建筑物是否在某个x坐标处可见呢?首先,建筑物的坐标中必须包含这个x坐标,其次,建筑物南边不能有另外一个建筑物也包含这个x坐标,并且不比它矮。代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100 + 5;
struct building{
    int id;
    double x,y,w,d,h;
}b[maxn];
int n;
double x[maxn*2];
int cmp(building a,building b){
    if(a.x == b.x) return a.y < b.y;
    return a.x < b.x;
}
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++) // 注意不是按y排序 所以要一直循环到最后
        if(b[k].y < b[i].y && b[k].h >= b[i].h && cover(k,mx)) return false;
    return true;
}
int main(){
    int kase = 0;
    while(scanf("%d",&n) && 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[i*2] = b[i].x;
            x[i*2+1] = b[i].x + b[i].w;
            b[i].id = i+1;
        }
        sort(b,b+n,cmp);
        sort(x,x+n*2);
        int m = unique(x,x+n*2) - x; //x坐标排序后去重,得到m个坐标
        if(kase++) putchar('\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++){
            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) printf(" %d",b[i].id);
        }
        putchar('\n');
    }
    return 0;
}
另外一种思路(枚举加区间覆盖): 先枚举每个建筑物,把可能覆盖的建筑物保存下来,然后就变成一个区间覆盖问题,判断能完全覆盖的就是会被挡住。我更喜欢这个思路哈哈,代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 105;
struct build{
    int id,x,y,w,d,h;
}city[maxn],save[maxn];
int n;
int cmp(build a,build b){
    if(a.x == b.x) return a.y < b.y;
    return a.x < b.x;
}
bool judge(build a){
    int cnt = 0;
    for(int i = 0;i < n;i++){
        build b = city[i];
        if(b.y >= a.y) continue;
        if(b.h < a.h) continue;
        if(b.x >= a.x + a.w || b.x + b.w <= a.x) continue;
        save[cnt++] = b;
    }
    if(!cnt) return true;
    int t = a.x;
    for(int i = 0;i < cnt;i++){
        if(t < save[i].x) return true;
        t = max(t,save[i].x + save[i].w);
    }
    if(t < a.x + a.w) return true;
    return false;
}
int main(){
    int kase = 0;
    while(scanf("%d",&n) && n){
        for(int i = 0;i < n;i++){
            scanf("%d%d%d%d%d",&city[i].x,&city[i].y,&city[i].w,&city[i].d,&city[i].h);
            city[i].id = i + 1;
        }
        sort(city,city + n,cmp);
        if(kase++) putchar('\n');
        printf("For map #%d, the visible buildings are numbered as follows:\n%d",kase,city[0].id);
        for(int i = 1;i < n;i++){
            if(judge(city[i])) printf(" %d",city[i].id);
        }
        putchar('\n');
    }
    return 0;
}

转载于:https://www.cnblogs.com/JingwangLi/p/10202737.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值