码迷,mamicode.com
首页 > 其他好文 > 详细

POJ #1328 Radar Installation 区间贪心 数学题(雾

时间:2018-02-10 15:50:57      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:图片   install   name   ==   ima   splay   color   end   desc   

Description


 

  问题的描述和测试样例如下:

    问题描述

    测试样例

 

思路


 

  吐槽时刻,这道题要特别注意精度问题,岛屿位置和雷达半径是整数,如果当成 double 型计算会导致 TLE。这个狗血的TLE一度让我怀疑C++ vector 是不是真的比内置数组慢太多了...事实证明 c++ 的 vector 当成定长数组计算的话还是很快的。

  回到原题,读完问题后,我们发现从无解情况入手是比较容易的。什么时候会无解呢?即存在一个以岛屿位置为圆心、雷达覆盖半径为半径的圆与 y = 0 联立后都没有解,即 delta < 0 ,化简后可以表示为 yi - d > 0 。

  那么什么时候会有解呢?delta >= 0 时会有解,而且方程联立后会得到两个根,雷达必须修在这两个根之间才能保证覆盖到该岛屿。很显然不需要为每个岛屿都修一个雷达站,因为如果两个岛屿在 x 轴上的根的范围是存在交集的话,就可以只修一个雷达站在交集的范围里。

  这时候贪心策略就出来了:我们先对 x 轴上的根区间以左根的大小进行一次排序,然后拿第一个根区间和第二个根区间的交集 tmp 去往后比对,如果之后的根区间和它交集为空,那么代表当前修的雷达站覆盖不了之后的岛屿,需要在这个根区间里再修一个雷达站,并把 tmp 替换成这个新的根区间;如果之后的根区间和它有交集,那么把 tmp 替换为当前的交集,代表当前修的雷达站只有在当前的这个区间里,才能覆盖当前岛屿 ... 如此比对,直到最后一个根区间比对完毕。

  举个例子,现在有四个岛屿以及建雷达时能被覆盖的根区间分别为 (-8, 2) 、(-7, -1)、(0, 0)、(1, 11) 。抽象成二维平面图如下:

    技术分享图片

  取第一个根区间和第二个根区间的交集为 tmp, tmp 为 [-7, -1] 。它和之后的 [0, 0] 比对后,发现交集为空,那么就需要在 [0, 0] 内多修一个雷达站,并替换 tmp 为新的根区间 [0, 0]。之后发现和 [1, 11] 的交集还是为空,那么在 [1, 11] 内多修一个雷达站,并替换 tmp 为 [1, 11] 。最后得到结果为 3。

  在实际敲代码时,可以把 tmp 区间换为一个记录交集右边界的变量。

  

技术分享图片
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cmath>
using namespace std;

struct Island {
    int x;
    int y;
    double delta;
    double left_root;
    double right_root;
};
const int MAX_N = 1000;
vector<Island> vec1; //vec1 存储岛屿信息

bool cmp (const Island& a, const Island& b) {
    return a.left_root < b.left_root;
}

int main(void) {
    int case_num = 0;
    int n; //岛屿数
    int d; //雷达覆盖半径
    while( cin >> n >> d) {
        if (n == 0 && d == 0) break;
        case_num++;
        vec1.resize(n+1);
        bool is_all_cover = true;
        for (int i = 1; i <= n; i++) {
            cin >> vec1[i].x >> vec1[i].y;
            vec1[i].delta = d * d - vec1[i].y * vec1[i].y; //将系数4忽略后的delta,便于计算开方
            //与y = 0 联立,有解时
            if (vec1[i].delta >= 0) {
                double sqrt_val = sqrt(vec1[i].delta);
                vec1[i].left_root = vec1[i].x - sqrt_val;
                vec1[i].right_root = vec1[i].x + sqrt_val;
            }
            //存在一个岛屿无法被覆盖,问题无法解决
            else {
                is_all_cover = false;
            }
        }
        //无解情况, 1.雷达覆盖半径是负数 2.存在岛屿无法被覆盖
        if (d < 0) {
            cout << "Case " << case_num << ": " << -1 << endl;
            continue;
        }
        if (!is_all_cover){
            cout << "Case " << case_num << ": " << -1 << endl;
            continue;
        }
        //有解情况,解决雷达站重复覆盖问题
        std::sort(vec1.begin() + 1, vec1.end(), cmp);
        int radar_num = 1; //雷达站数目
        double tmp = vec1[1].right_root;
        for (int i = 2; i <= n; i++) {
            if (vec1[i].left_root > tmp) {
                radar_num++;
                tmp = vec1[i].right_root;
            }
            else if (vec1[i].right_root < tmp) {
                tmp = vec1[i].right_root;
            }
        }
        cout << "Case " << case_num << ": " << radar_num << endl;
        vec1.clear();
    }
    vec1.clear();
    vector<Island>().swap(vec1);
    return 0;
}
View Code

 

  

  

POJ #1328 Radar Installation 区间贪心 数学题(雾

标签:图片   install   name   ==   ima   splay   color   end   desc   

原文地址:https://www.cnblogs.com/Bw98blogs/p/8438792.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!