UVA 221 - Urban Elevations(离散化)!!!!!!

题意:给出一张俯视图。给出N个建筑物的左下标,长度,宽度,高度。现在求,从南面看,能看到那些建筑?

Sample Input

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
0

Sample Output

For map #1, the visible buildings are numbered as follows:
5 9 4 3 10 2 1 14

unique()函数是一个去重函数,STL中unique的函数 unique的功能是去除相邻的重复元素(只保留一个)还有一个容易忽视的特性是它并不真正把重复的元素删除。eg.int num[100]; unique(num,mun+n)返回的是num去重后的尾地址,之所以说比不真正把重复的元素删除,其实是,该函数把重复的元素一到后面去了,然后依然保存到了原数组中,然后返回去重后最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序。

离散化

基本思想就是在众多可能的情况中“只考虑我需要用的值”。

eg.1

给定平面上n个点的坐标,求能够覆盖所有这些点的最小矩形面积。这个问题难就难在,这个矩形可以倾斜放置(边不必平行于坐标轴)。

这里的倾斜放置很不好处理,因为我们不知道这个矩形最终会倾斜多少度。假设我们知道这个矩形的倾角是α,那么答案就很简单了:

矩形面积最小时四条边一定都挨着某个点。也就是说,四条边的斜率已经都知道了的话,只需要让这些边从外面不断逼近这个点集直到碰到了某个点。

你不必知道这个具体应该怎么实现,只需要理解这可以通过某种方法计算出来,毕竟我们的重点在下面的过程。

我们的算法很显然了:枚举矩形的倾角,对于每一个倾角,我们都能计算出最小的矩形面积,最后取一个最小值。

这个算法是否是正确的呢?我们不能说它是否正确,因为它根本不可能实现。矩形的倾角是一个实数,它有无数种可能,你永远不可能枚举每一种情况。我们说,矩形的倾角是一个“连续的”变量,它是我们无法枚举这个倾角的根本原因。我们需要一种方法,把这个“连续的”变量变成一个一个的值,变成一个“离散的”变量。这个过程也就是所谓的离散化。
    我们可以证明,最小面积的矩形不但要求四条边上都有一个点,而且还要求至少一条边上有两个或两个以上的点。试想,如果每条边上都只有一个点,则我们总可以把这个矩形旋转一点使得这个矩形变“松”,从而有余地得到更小的矩形。于是我们发现,矩形的某条边的斜率必然与某两点的连线相同。如果我们计算出了所有过两点的直线的倾角,那么α的取值只有可能是这些倾角或它减去90度后的角(直线按“\”方向倾斜时)这么C(n,2)种。我们说,这个“倾角”已经被我们 “离散化”了。虽然这个算法仍然有优化的余地,但此时我们已经达到了本文开头所说的目的。

eg.2

大意是给定平面上的n个矩形(坐标为整数,矩形与矩形之间可能有重叠的部分),求其覆盖的总面积。平常的想法就是开一个与二维坐标规模相当的二维Boolean数组模拟矩形的“覆盖”(把矩形所在的位置填上True)。可惜这个想法在这里有些问题,因为这个题目中坐标范围相当大(坐标范围为-10^8到10^8之间的整数)。但我们发现,矩形的数量n<=100远远小于坐标范围。每个矩形会在横纵坐标上各“使用”两个值,  100个矩形的坐标也不过用了-10^8到10^8之间的200个值。也就是说,实际有用的值其实只有这么几个。这些值将作为新的坐标值重新划分整个平面,省去中间的若干坐标值没有影响。我们可以将坐标范围“离散化”到1到200之间的数,于是一个200*200的二维数组就足够了。实现方法正如本文开头所说的“排序后处理”。对横坐标(或纵坐标)进行一次排序并映射为1到2n的整数,同时记录新坐标的每两个相邻坐标之间在离散化前实际的距离是多少。这道题同样有优化的余地。

 
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=100+5;

struct Building{
    int id;
    double x,y,w,d,h;
    bool operator < (const Building& rhs) const{         //重载运算符<
        return x<rhs.x||(x==rhs.x&&y<rhs.y);  // true x未被rhs挡住(x在rhs.x的左边  或者  x与rhs.x相同,但x在rhs.x前面,即y<rhs.y)
    }
}b[maxn];

int n;
double x[maxn*2];             //用来存储各个建筑物的左右边界

bool cover(int i,double mx)                  //判断建筑物i在x=mx处是否可见
{
    return b[i].x<=mx&&b[i].x+b[i].w>=mx;       //true时  b[i]在mx处可见
}

bool visible(int i,double mx)
{
    if(!cover(i,mx))return false;           //b[i]在mx处不可见
    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;    //b[i]被b[k]挡住
    return true;                                   //b[i]在mx处可见
} 

int main()
{
    int kase=0;
    while(scanf("%d",&n)==1&&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);               //按照结构体中重载的运算符<排序,x小的在前面,x相同y小的在前面
        /*cout<<endl;
        for(int i=0;i<n;i++)
            cout<<b[i].id<<" "<<b[i].x<<" "<<b[i].y<<" "<<b[i].h<<" "<<b[i].d<<endl;*/
        sort(x,x+n*2);
        int m=unique(x,x+n*2)-x;               //x坐标排序后去重,得到m个坐标
                                              //x的前m项为建筑群从左到右的左边界有边界
        //for(int i=0;i<n*2;i++)cout<<x[i]<<endl;
        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++){
            bool vis=false;
            for(int j=0;j<m-1;j++){
                if(b[i].x+b[i].w<x[j])break;       //增添这句后,简化程序,当b[i]建筑的右边界都小于x[j]时在其中点处肯定不可见
                if(visible(i,(x[j]+x[j+1])/2)){      //true  b[i]在各个左右边界之间的中点处可见
                    vis=true;
                    break;
                }
            }
                if(vis)printf(" %d",b[i].id);
        }
        printf("\n");
    }
    //system("pause");
    return 0;
}

 
时间: 2024-11-17 10:46:23

UVA 221 - Urban Elevations(离散化)!!!!!!的相关文章

UVa 221 Urban Elevations 城市正视图 离散化初步 无限化有限

转载请注明: 仰望高端玩家的小清新 http://www.cnblogs.com/luruiyuan/ 题目大意: 题目传送门:UVa 221 Urban Elevations 给出城市中建筑物的x, y 坐标的最小值:x,y , 再给出其以左下角为坐标原点的关于x轴.y轴上的长度 w, 和 d,最后给出建筑物的高度 h,将建筑物的正视图中,能够看到的建筑物的id打印出来:要求先打印x小的,当x相同时,打印y小的.为了简化,假定建筑物都是长方体.同时,每个输出之间要用一个空行隔开 One bla

UVA 221 Urban Elevations

思路: 一些解释: ①:建筑的排序: 下面是以输入顺序为标号,在数组bd中的顺序: 排序后在数组bd中的顺序: 以后我们比较就按这个顺序 ②:x坐标的排序 x的内容是每一个建筑的左边界和右边界,我们把他去重排序后,就是一个一个的坐标,相邻的x形成一个区间, 取它的中点来判断,比如,样例输入的bd[1]就是遍历所有的区间来判断是否可见.下面附上调试截图. x: sort后的x: unique后的x: 1 #include<cstdio> 2 #include<algorithm> 3

UVA - 221(区间覆盖)

 Urban Elevations  An elevation of a collection of buildings is an orthogonal projection of the buildings onto a vertical plane. An external elevation of a city would show the skyline and the faces of the ``visible" buildings of the city as viewed fr

I - Urban Elevations

uva 221 提供个房子的坐标以及房子宽度和高度,要求你求从南边看过去,可以看到的房子有哪些 PS:一定要注意题目的这句:One blank line must separate output from consecutive input records.不然会直接报错 可以直接使用暴力做,不过要注意枚举方式,在无序的情况下直接考虑每个房子对正研究的房子的影响显然是不现实的,因为可能有房子刚好当前边一部分,或中间一部分,或后面一部分,这个不好统一,所以事先排序能明确统计 #include <i

UVa 221 (STL 离散化) Urban Elevations

题意: 作图为n个建筑物的俯视图,右图为从南向北看的正视图,按从左往右的顺序输出可见建筑物的标号. 分析: 题中已经说了,要么x相同,要么x相差足够大,不会出现精度问题. 给这n个建筑物从左往右排序,每个建筑物的两个端点,排序去重以后可以得到m个相邻的小区间.枚举这些区间,判断建筑物是否可见. 离散化刚开始接触这个词,感觉十分高冷.现在来看倒是很形象,因为是浮点数,所以不可能枚举所有的横坐标,但可以分割成若干的小区间,这个进行判断.即:将无限变为有限. 再说一下unique函数,调用之前必须先排

Urban Elevations UVA - 221

题目大意:给出建筑的俯视图,以及每个建筑的左下角坐标,宽度,长度,高度.求正视图可观察到的建筑的编号 思路:建筑物的可见性等于南墙的可见性,依据左下角排序后,逐个判断每个建筑是否可见.对南墙的x坐标进行排序,相邻两个x坐标之间的南墙可见性一致,通过判断这部分南墙中的特殊点(中间点)可以得到这部分墙的可见性.如果这部分墙可见,那么这部分墙 归属的建筑可见. #include<bits/stdc++.h> using namespace std; #define LL long long #def

UVa 221城市正视图(离散化)

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=157 题意:输入建筑物的x,y坐标,宽度,深度和高度,输出从南向北看时能看到的建筑物. 这道题需要用到离散化,将所有建筑物物的左右边界坐标存储起来,然后排序去重,那么任意两个相邻x坐标形成的区间要么是可见的,要么就是不可见的.这样只需在这个区间内任选一点(如中点),当该建筑物可见时,首先它的

UVA 221 城市化地图(离散化)

题意: 分析: 记录一个一开始就想错的观点, 以为只要把x 和 width放大到到足够大(例如10000倍,倍数越高精度越高),然后排序填充一下数轴就可以,就可以解决x坐标是小数的问题.但这样打了一下,发现第一计算速度很慢(放大后n倍计算量也同时放大n^2倍), 第二是无法处理覆盖与重叠的部分, 只会保留数轴中最大的部分, 无法保留在高楼南边的矮楼.

hdu 2771(uva 12171) Sculpture bfs+离散化

题意: 给出一些边平行于坐标轴的长方体,这些长方体可能相交.也可能相互嵌套.这些长方体形成了一个雕塑,求这个雕塑的整体积和表面积. 题解: 最easy想到直接进行bfs或者dfs统计,但此题的麻烦之处在于求整个雕塑的外表面积和雕塑内部可能出现四个长方体所搭成的空心.空心不能计算到表面积中,可是计算整体积却要计入,于是直接bfs或者dfs不优点理.于是,能够想到直接统计整个雕塑外围的全部小方块.就可以非常方便地求出雕塑地表面积和体积(雕塑地整体积==整个空间地体积-外围想方块的体积),另一点就是因