• 算法习题---5.12城市正视图<离散化应用>(Uva221)*****


    一:题目

    给定n坐房子的西南角坐标x, y.还有宽度w,长度d(其实没用),高度h。问从南面看过去能看到几座房子。

    城市俯视图和主视图

    注意:

    输出主视图中能够看到的所有建筑物按照左下角x坐标从小到大进行排序。左下角x坐标相同时,按照y轴坐标从小到大排序

    (一)样例输入

    14    //14个建筑物
    160 0 30 60 30  //x,y轴,横向宽度w,纵向宽度d,高度h
    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  //结束符号

    (二)样例输出

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

    二:代码实现

    (一)思路分析

    判断可见性比较麻烦,因为一个建筑物可能只是部分可见,无法枚举所有x坐标,来查看这个建筑物在该点处是否可见,因为x坐标有无穷个。
    解决方法:离散化--->将无穷变有限

    具体实现:

    将所有x坐标排序去重,则任意两个相邻的x坐标形成的区间具有相同属性,可见或者不可见。我们取区间中任意一点(取中点)判断可见性

    (二)代码实现

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define MAX 101
    
    struct  Builds
    {
        int id;
        double x, y, w, d, h;
        bool operator<(struct Builds& other) const    //按题意输出要求设置:x从小到大,当x相同时,y从小到大
        {
            return x < other.x || (x == other.x&&y < other.y);
        }
    }b[MAX];    //用于保存建筑信息
    
    double check_pos[MAX * 2];    //用于保存所有检测点
    int n;    //获取总建筑数量
    
    bool cover(int i, double x_p)    //用于检测该建筑是否在x轴上面包含了该点x_p
    {
        return b[i].x <= x_p&&b[i].x + b[i].w >= x_p;
    }
    
    bool visiable(int i, double x_p)    //用于检测建筑i在x_p上是否可见
    {
        //1.先看该建筑物是否包含这个x_p点
        if (!cover(i, x_p))
            return false;
        //2.看包含这个点的其他建筑物是否高于自己
        for (int j = 0; j < n; j++)
        {
            if (j==i) continue;
            if (cover(j, x_p) && b[j].h>=b[i].h&& b[j].y < b[i].y)    //cover包含该点,h高于i建筑,y且在i建筑前面
                return false;
        }
        return true;
    }
    
    int main()
    {
        freopen("data5_12.in", "r", stdin);
        freopen("data5_12.out", "w", stdout);
        int count = 1;
    
        while (cin >> n&&n != 0)
        {
            //先获取所有建筑信息
            for (int i = 0; i < n; i++)
            {
                cin >> b[i].x >> b[i].y >> b[i].w >> b[i].d >> b[i].h;    //获取建筑信息
                b[i].id = i + 1;
                check_pos[i * 2] = b[i].x;    //获取检测点信息
                check_pos[i * 2 + 1] = b[i].x + b[i].w;
            }
            
            sort(b, b + n);    //对建筑物进行排序 按照重载<进行排序
            sort(check_pos, check_pos+2 * n);    //对检测点进行排序 
    
     //unique返回去重后的最后一个元素的位置double*
            int m = unique(check_pos, check_pos + 2 * n)-check_pos;    //对监测点进行去重
    
            //输出信息
            cout << "For map #" << count++ << " ,the visible buildings are numbered as followws:" << endl;
            //进行判断各个建筑物的可见性
            for (int i = 0; i < n; i++)
            {
                bool flag = false;
                for (int j = 0; j < m - 1; j++)
                {
                    double central_pos = (check_pos[j] + check_pos[j + 1]) / 2;    //找到中心点
                    if (visiable(i, central_pos))
                    {
                        flag = true;
                        break;
                    }
                }
                if (flag)
                    cout << b[i].id << " ";
            }
        }
    
        freopen("CON", "r", stdin);
        freopen("CON", "w", stdout);
        return 0;
    }
  • 相关阅读:
    博弈论(SG函数):HNOI 2007 分裂游戏
    博弈论(二分图匹配):NOI 2011 兔兔与蛋蛋游戏
    博弈论(男人八题):POJ 1740 A New Stone Game
    动态规划(树形DP):HDU 5834 Magic boy Bi Luo with his excited tree
    杂项(最小表示法):HZOI 2015 Glass Beads
    如何避免死锁
    死锁的四个必要条件
    线程安全和可重入函数之间的区别和联系
    信号量 sem_undo设置
    linux管道的容量和内部组织方式
  • 原文地址:https://www.cnblogs.com/ssyfj/p/11523547.html
Copyright © 2020-2023  润新知