• [蓝桥杯训练] 第八届(2017)省赛 C/C++ A组 T10


    1. 题目

    X星球的一批考古机器人正在一片废墟上考古。
    该区域的地面坚硬如石、平整如镜。
    管理人员为方便,建立了标准的直角坐标系。

    每个机器人都各有特长、身怀绝技。它们感兴趣的内容也不相同。
    经过各种测量,每个机器人都会报告一个或多个矩形区域,作为优先考古的区域。

    矩形的表示格式为(x1,y1,x2,y2),代表矩形的两个对角点坐标。

    为了醒目,总部要求对所有机器人选中的矩形区域涂黄色油漆。
    小明并不需要当油漆工,只是他需要计算一下,一共要耗费多少油漆。

    其实这也不难,只要算出所有矩形覆盖的区域一共有多大面积就可以了。
    注意,各个矩形间可能重叠。

    本题的输入为若干矩形,要求输出其覆盖的总面积。

    输入格式:
    第一行,一个整数n,表示有多少个矩形(1<=n<10000)
    接下来的n行,每行有4个整数x1 y1 x2 y2,空格分开,表示矩形的两个对角顶点坐标。
    (0<= x1,y1,x2,y2 <=10000)

    输出格式:
    一行一个整数,表示矩形覆盖的总面积面积。

    例如,
    输入:
    3
    1 5 10 10
    3 1 20 20
    2 7 15 17

    程序应该输出:
    340

    再例如,
    输入:
    3
    5 2 10 6
    2 7 12 10
    8 1 15 15

    程序应该输出:
    128

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 2000ms


    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    注意:
    main函数需要返回0;
    只使用ANSI C/ANSI C++ 标准;
    不要调用依赖于编译环境或操作系统的特殊函数。
    所有依赖的函数必须明确地在源文件中 #include <xxx>
    不能通过工程设置而省略常用头文件。

    提交程序时,注意选择所期望的语言类型和编译器类型。

    2. 分析

    2.1 如何计算面积

      因为坐标全是整数,这样就可以用比较简单的方法--记录坐标

      但是会有TLE的问题,请自行取舍。

      以下是一个简单的图例:

      

      给出了x和y这两个对角的坐标,由于全是整数(离散),我们可以直接用两个for循环来计算面积。

    2.2 输入坐标的两种可能

      对角有两种情况,我们若想使用坐标法求面积,必须统一从左下角往右上角遍历,因此需要把两种类型的对角统一变成左下-右上形式的。方法如下:

     

    2.3 如何解决重叠问题

      我的想法是比较简单的:建立一个10000*10000的bool型二维数组,对于每次输入的坐标,将对应区域内的bool设为true,最后厉遍统计true的数量就是面积。

    void Print(int x1, int y1, int x2, int y2, bool plain[][10001]) { //第一种方法
        int xBegin = min(x1,x2); //这是左下角的x
        int yBegin = min(y1,y2); //这是左下角的y
        int xEnd = max(x1,x2);  //这是右上角的x
        int yEnd = max(y1,y2);   //这是右上角的y
        for (int i=xBegin; i<xEnd; i++) {
            for (int j=yBegin; j<yEnd; j++) {
                plain[i][j] = true;//暴力置位
            }
        }
    }

      无脑暴力,最为致命。这样做的好处是:你根本不用考虑重复的问题,因为同一个位置设置多少次也不会有任何改变,可以放心使用。当然,必须要注意的是,10000*10000的数组是会爆栈的,必须用new分配堆内存给该变量。

      或者你也可以使用STL里面的set:构造一个字符串,格式为xxx-yyy,其中xxx为x坐标,yyy为y坐标,之后将其插入集合中,由于同样的坐标具有一样的形式,无法重复插入,最后只需要输出set.size()就能得到答案。(该方法不容易爆,推荐使用)  

    void Print(int x1, int y1, int x2, int y2, set<string> &st) { //第二种方法,注意&不要漏了
        int xBegin = min(x1,x2);
        int yBegin = min(y1,y2);
        int xEnd = max(x1,x2);
        int yEnd = max(y1,y2);    
        for (int i=xBegin; i<xEnd; i++) {
            for (int j=yBegin; j<yEnd; j++) {
                ostringstream s;
                string str;
                
                s.clear();
                s << i;
                str += s.str();
                str += '-';
                s.clear();
                s << j;
                str += s.str();
                st.insert(str);
            }
        }
    }

    3. 代码

     1 #include <iostream>
     2 #include <sstream>
     3 #include <fstream>
     4 #include <algorithm>
     5 #include <vector>
     6 #include <set>
     7 #include <list>
     8 #include <string>
     9 #include <map>
    10 #include <cmath>
    11 #include <cstring>
    12 #include <cstdlib>
    13 #include <windows.h>
    14 
    15 using namespace std;
    16 
    17 
    18 void Print(int x1, int y1, int x2, int y2, set<string> &st);
    19 #define DEBUG 1  //当你使用官方的txt测试数据时,可以将该宏置位,并在第27行更改文件名,这样就可以从txt读入测试数据,最后自行对照对应的out.txt
    20 
    21 
    22 int main() {
    23     set<string> st;
    24     int n,x1,y1,x2,y2,count;
    25     long time = GetTickCount();
    26 #if DEBUG
    27     ifstream fin( "in1.txt" ,ios::in);
    28     fin >> n;
    29     for (int i=0; i<n; i++) {
    30         fin >> x1 >> y1 >> x2 >> y2;
    31         Print(x1,y1,x2,y2,st);
    32         count = st.size();
    33     }
    34 #else
    35     cin >> n;
    36     for (int i=0; i<n; i++) {
    37         cin >> x1 >> y1 >> x2 >> y2;
    38         Print(x1,y1,x2,y2,st);
    39         count = st.size();
    40     }
    41 #endif
    42     time =  GetTickCount() - time;  //计算时间
    43     cout << st.size() << endl <<"time:" << time <<  " ms" << endl;
    44     return 0;
    45 }
    46 
    47 void Print(int x1, int y1, int x2, int y2, set<string> &st) {
    48     int xBegin = min(x1,x2);
    49     int yBegin = min(y1,y2);
    50     int xEnd = max(x1,x2);
    51     int yEnd = max(y1,y2);    
    52     for (int i=xBegin; i<xEnd; i++) {
    53         for (int j=yBegin; j<yEnd; j++) {
    54             ostringstream s;
    55             string str;
    56             
    57             s.clear();
    58             s << i;
    59             str += s.str();
    60             str += '-';
    61             s.clear();
    62             s << j;
    63             str += s.str();
    64             st.insert(str);
    65         }
    66     }
    67 }

    4. 运行结果

     

    最后两个严重TLE,尤其是是第五个测试点,不过答案至少是对了,能拿不少分。

    待我更多学习之后再来优化。

  • 相关阅读:
    #与javascript:void(0)的区别
    单选框、复选框、下拉列表
    数据类型后的“?”
    c#中日期的处理
    日期控件html
    javascript获取后台传来的json
    Hashtable语法简介
    Hashtable(哈希表)
    Dictionary 字典
    远程SQL Server连接不上
  • 原文地址:https://www.cnblogs.com/sser-invincible/p/8624853.html
Copyright © 2020-2023  润新知