zoukankan      html  css  js  c++  java
  • 贪心算法----区间覆盖问题(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 }

      结果:

        

  • 相关阅读:
    盒模型新增样式
    css3 文字处理
    popupWindow的用法(1)
    spinner适配器
    layer-list解决listView中相邻item之间线的重叠的问题
    安卓中常用的shape,selector,layer-list
    Pagerstwich tab样式加下拉刷新(三)
    PagerSwitch tab样式加下拉刷新(二)
    PagerSwitch tab样式加上下拉刷新(一)
    listview中textview响应部分文本点击事件
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10364579.html
Copyright © 2011-2022 走看看