贪心问题 区间覆盖 —— 喷水装置(二)

喷水装置(二)

时间限制:3000 ms  |  内存限制:65535 KB

难度:4

描述
有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿。请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿。
输入
第一行输入一个正整数N表示共有n次测试数据。
每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。
随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。
输出
每组测试数据输出一个正整数,表示共需要多少个喷水装置,每个输出单独占一行。
如果不存在一种能够把整个草坪湿润的方案,请输出0。
样例输入

2
2 8 6
1 1
4 5
2 10 6
4 5
6 5

样例输出

1
2

题解:

题目分析:本题可以看作是区间覆盖问题,将每个圆的喷射范围映射到区间内。可转换为:如图,数轴上有n个区间[a-x,a+x](如图),选择尽量少的区间覆盖[0,w]。

贪心策略

把各区间按照 起点 从小到大排序,从前向后遍历,然后每次选择 从当前位置起点 开始的最长区间,并以这个区间的最右端 为新的起点,继续选择,直到找不到区间 覆盖当前位置起点 或者 当前位置起点 已经到达线段末端。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;

const int maxn = 10000 + 20;
double Distance(double ri, double h);
void solve();

struct Water {
    double    left,
            right;
    Water(double lh = 0, double rh = 0) : left(lh), right(rh) {
    }
} wats[maxn];

bool cmp(const Water& a, const Water& b)
{
    return a.left < b.left;
}

double Distance(double ri, double h)
{
    return sqrt(ri * ri - h * h / 4);
}

void solve()
{
    int N;
    int n, w, h;

    int xi, ri;

    cin >> N;

    while (N--)
    {
        int cnt = 0;
        int ans = 0;

        cin >> n >> w >> h;

        for (int i = 0; i < n; i++)
        {
            cin >> xi >> ri;

            if (ri*2 < h) continue;
            double dis = Distance(ri, h);
            wats[cnt].left = xi - dis;
            wats[cnt++].right = xi + dis;

        }
        //排序的范围是  cnt !!!!!! 不是 n 了!!阿西吧,好气哦
        sort(wats, wats + cnt, cmp);

        double current_sum = 0;
        int flag = 1;

        while (current_sum < w)
        {
            double max = 0;

//                每次选择从当前起点S开始的最长区间,并以这个区间的右端点为新的起点
            for (int j = 0; j < cnt; j++)
            {
                if (wats[j].left <= current_sum && wats[j].right - current_sum > max) {
                    max = wats[j].right - current_sum;     //选择从 current_Sum开始的,最长区间
                }
            }
            if (max)
            {
                ans++;
                current_sum += max;      //当前位置向后移动
            }
            else
            {
                //最后一个区间的末尾 不能 比 current_sum 大 ==> 显然不存在解
                flag = 0;
                break;
            }
        }
        if (!flag) {
            cout << 0 << endl;
        }
        else {
            cout << ans << endl;
        }
    }
}

int main()
{
    solve();

    return 0;
}
 

原文地址:https://www.cnblogs.com/douzujun/p/8406107.html

时间: 2024-08-28 12:45:29

贪心问题 区间覆盖 —— 喷水装置(二)的相关文章

POJ 2376 Cleaning Shifts (贪心,区间覆盖)

题意:给定1-m的区间,然后给定n个小区间,用最少的小区间去覆盖1-m的区间,覆盖不了,输出-1. 析:一看就知道是贪心算法的区间覆盖,主要贪心策略是把左端点排序,如果左端点大于1无解,然后, 忽略小于1的部分(如果有的话),再找最长的区间,然后把这个区间的右端点作为下次寻找的起点, 再找最大区间,直到覆盖到最后. 注意:首先要判断好能不能覆盖,不能覆盖就结束,有可能会提前结束,也要做好判断,我就在这WA了好几次, 悲剧...其他的就比较简单了,不用说了. 代码如下: #include <ios

贪心算法----区间覆盖问题(POJ2376)

题目: 题目的大概意思是约翰这个农民有N条牛,这些牛可以在一天中的某个时间段可以进行工作,他想把这个时间段分成若干个片段让这些牛去进行打扫任务,你的任务是安排尽量少的牛然后可以完成分成这些片段的打扫任务. 输入: 第一行两个数,第一个数代表牛的个数N,第二个数代表时间T,表示的是时间段[1,T]. 下面的N行每行表示牛工作的时间段. 输出: 输出使用最少的牛的数量. 思路分析:这道题目完全就是一个区间覆盖问题的裸题,求解过程,将每个牛工作的区间按左端点递增排序,如果左端点相同,按右端点递增顺序排

uva 10020 Minimal coverage(贪心,区间覆盖)

这道题一读就是经典的区间问题,是区间覆盖,敲过之后还有花了很长的调试时间,还是我不熟练,现在做题确实挺慢 的,简单题目也要做好久,没事,慢慢来.最重要的要确保正确率和心态问题,认真对待,调试找到了好多bug,一些 细节问题...都是刚开始没有注意到的.交了之后RE,在数组上多加了两个0.A了,,uva老是不提示数据有多大, 所以只能乱开... 思路: 先对区间按左边的点进行排序,如果当前需要涵盖的区间为[x,y],那么在排序的区间中到左边小于x,右 边最大的那个区间,设为Max,然后更新想找的区

贪心问题 区间覆盖 —— POJ 2376 Cleaning Shift

题目:http://poj.org/problem?id=2376 题意:就是 N 个区间, 输入 N 个区间的 [begin, end],求能用它们覆盖区间[1,T]的最小组合. 题解: 1. 首先对所有奶牛的排序,按照开始时间升序排序. 2. 更新 起点 为 上一次的终点 + 1,并寻找覆盖起点,且终点最远的区间 #include <iostream> #include <cstdlib> #include <cstdio> #include <algorit

D 贪心,区间覆盖问题

Given several segments of line (int the X axis) with coordinates [Li , Ri ]. You are to choose the minimal amount of them, such they would completely cover the segment [0, M]. Input The first line is the number of test cases, followed by a blank line

nyoj 12——喷水装置二——————【贪心-区间覆盖】

喷水装置(二) 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿.请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿. 输入 第一行输入一个正整数N表示共有n次测试数据.每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度.随后的n行,

南阳OJ-12-喷水装置(二)贪心+区间覆盖

题目链接: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=12 题目大意: 有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿.请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿. 传送门:喷水装置(一) 思路: 区间覆盖问题,每个点有一段喷水区间,按照左端点排序即可,设置两变量begin, end,依次扫过去,每

UVa 10382 Watering Grass (区间覆盖贪心问题+数学)

题意:有一块长为l,宽为w的草地,在其中心线有n个喷水装置,每个装置可喷出以p为中心以r为半径的圆, 选择尽量少的装置,把草地全部润湿. 析:我个去啊,做的真恶心,看起来很简单,实际上有n多个坑啊,首先这个题,应该可以看出来是贪心算法, 具体的说是区间覆盖问题,这个问题总体来说不难,但是在这有了巨多的坑.要注意以下几点: 1.这是一个草坪,不是线段,首先你要先把实验室转化为线段. 2.这个喷水装置喷出是圆,不是矩形,要运用数学知识进行运算. 3.输入的半径的两倍如果小于等于宽度,就得忽略不记.因

贪心--区间覆盖及区间选点问题

区间覆盖: 数轴上有若干区间,选用最少的线段覆盖指定区间. 区间选点:选用最少的区间使每个区间内至少有一个点 样题1: J - Muddy roads Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description Farmer John has a problem: the dirt road from his farm to town has suffered in the re