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

题目:

  

  题目的大概意思是约翰这个农民有N条牛,这些牛可以在一天中的某个时间段可以进行工作,他想把这个时间段分成若干个片段让这些牛去进行打扫任务,你的任务是安排尽量少的牛然后可以完成分成这些片段的打扫任务。

  输入:

    第一行两个数,第一个数代表牛的个数N,第二个数代表时间T,表示的是时间段[1,T]。

    下面的N行每行表示牛工作的时间段。

  输出:

    输出使用最少的牛的数量。

  思路分析:这道题目完全就是一个区间覆盖问题的裸题,求解过程,将每个牛工作的区间按左端点递增排序,如果左端点相同,按右端点递增顺序排列。设置start变量初始化为时间段的左端点,在这些区间中找到满足左端点小于start并且右端点尽量往右靠的区间,然后将这个区间的右端点设置为end变量,这样就找到了一个区间,然后将start变量更新为end变量,然后再在剩下的区间继续寻找左端点小于start并且右端点尽量往右靠的区间,然后再将这个区间的右端点设置为end变量,这样就又找到了一个区间,如此循环下去,直到end大于时间段的右端点,退出循环,这样就能找出使用哪些区间能够覆盖这个时间段了。解答这道题目在循环中使用一个变量计数即可。

  贪心思想:要求用最少的区间进行覆盖,那么选取的区间必然要尽量长,而已覆盖到的区域之前的地方已经不用考虑了,可以理解成所有可覆盖的左端点都已被覆盖了,那么能够使得区间更长的取决于右端点,左端点没有太大的意义,所以选择右端点来覆盖。而且在循环的过程中,相当于很多的子问题最优组成了全局的最优。找到每个能够使用的最长区间就相当于子问题最优,而每个子问题最优就构成了使用的区间数最少这个全局最优。

  代码:

 1 import java.util.Arrays;
 2 import java.util.Scanner;
 3
 4 public class 区间覆盖问题 {
 5     public static void main(String[] args) {
 6         Scanner sc = new Scanner(System.in);
 7         int N = sc.nextInt();
 8         int T = sc.nextInt();
 9         Job[] jobs = new Job[N];
10         for (int i = 0; i < N; i++) {
11             jobs[i] = new Job(sc.nextInt(), sc.nextInt());
12         }
13         Arrays.sort(jobs);
14         int start = 1;// 要覆盖的目标点,end覆盖该点的所有区间中右端点最右
15         int end = 1;
16         int ans = 1;
17         for (int i = 0; i < N; i++) {
18
19             int s = jobs[i].s;
20             int t = jobs[i].t;
21
22             if (i == 0 && s > 1)
23                 break;
24
25             if (s <= start) {// 当前区间有可能覆盖start
26                 end = Math.max(t, end);// 更新更右的端点
27             } else {// 开始下一个区间
28                 ans++;// 上一个目标覆盖已经达成,计数加1
29                 start = end + 1;// 更新起点,设置一个新的覆盖目标
30                 if (s <= start) {
31                     end = Math.max(t, end);
32                 } else {
33                     break;
34                 }
35             }
36             if (end >= T) {// 当前的end超越了线段的右侧
37                 break;
38             }
39
40         }
41         if (end < T)
42             System.out.println(-1);
43         else
44             System.out.println(ans);
45     }
46
47     private static class Job implements Comparable<Job> {
48         int s;
49         int t;
50
51         public Job(int s, int t) {
52             this.s = s;
53             this.t = t;
54         }
55
56         /** 按照区间起点排序 */
57         @Override
58         public int compareTo(Job other) {
59             int x = this.s - other.s;
60             if (x == 0)
61                 return this.t - other.t;
62             else
63                 return x;
64         }
65     }
66 }

  结果:

    

原文地址:https://www.cnblogs.com/xiaoyh/p/10364579.html

时间: 2024-07-28 18:03:19

贪心算法----区间覆盖问题(POJ2376)的相关文章

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

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

贪心算法----区间调度问题

题目: 有n项工作,每项工作分别在si时间开始,在ti时间结束.对于每项工作,你都可以选择参与与否.如果选择了参与,那么自始至终都必须全程参与.此外,参与工作的时间段不能重复(即使是开始的瞬间和结束的瞬间的重叠也是不允许的).你的目标是参与尽可能多的工作,那么最多能参与多少项工作呢?  1≤n≤100000  1≤si≤ti≤109.这道题目还可以称作不相交区间问题. 输入: 第一行:n 第二行:n个整数空格隔开,代表n个工作的开始时间 第三行:n个整数空格隔开,代表n个工作的结束时间 样例输入

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

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

贪心算法-区间调度问题解之证明

一.贪心算法 定义:一个算法是贪心算法,如果它是通过一些小的步骤来一个求解,并且在每一步根据局部情况选择一个决定,使得某些主要的指标得到优化. 二.区间调度问题 1. 问题:我们有一组需求{1,2,3,......,N},第i个需求与一个开始时间s(i),结束时间f(i)相对应.如果没有两个需求在时间上重叠,我们就说需求的子集是相容的. 2. 目标:寻找一个最大的相容子集O. 3. 算法: 初始令R是所有需求的集合,设A为空 While ( |R| > 0 ) 选择一个最早结束的需求 把i加入到

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

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

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

UVa 10020 - Minimal coverage(区间覆盖、贪心)

算法入门经典关于区间覆盖的讲解: 8.4.6:区间覆盖问题 数轴上有n个区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t]. [分析] 突破口是区间的包含和排序扫描,不过要先进行一次预处理.每个区间在[s,t]外的部分应该首先被切除掉,因为他们的存在是没有意义的.在预处理后,在相互包含的情况下,小区间显然不应该考虑. 把区间按照a从小到大排序.如果区间1的七点不是s,无解,否则选择起点在s的最长区间.选择此区间[ai,bi]后,新的起点应该设置为bi,并且忽略所有区间在bi之前的部分