区间贪心:最小区间覆盖问题、PIPI的高速公路

梦想不抛弃苦心追求的人,只要不停止追求,你们会沐浴在梦想的光辉之中。再美好的梦想与目标,再完美的计划和方案,如果不能尽快在行动中落实,最终只能是纸上谈兵,空想一番。只要瞄准了大方向,坚持不懈地做下去,才能够扫除挡在梦想前面的障碍,实现美好的人生蓝图。区间贪心:最小区间覆盖问题、PIPI的高速公路,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

区间贪心:最小区间覆盖问题、PIPI的高速公路

问题1:

在这里插入图片描述
在这里插入图片描述

思路:

  本题是区间贪心的一种:在满足覆盖[L,R]区间的情况下,最少能选择多少个区间
  我们可以将线段(区间)按左端点从小到大排序,我们的贪心策略是每次所选择的区间使后面预留的空间最小,即尽可能多地占用[L,R]中的空间。为此,我们可以定义右极限rLimit,表示当前所遍历到的合法区间中r的最大值,初始化为L,每次我们从合法的备选区间(即l <= rLimit)中找出右端点r最大的区间并选择该区间,接着更新rLimit,使rLimit = r,持续该过程,直到rLimit >= R,我们便用最少的区间数覆盖了[L,R]

代码:

import java.util.*;

public class Main {
    static List<Region> array = new ArrayList<>();
    public static void main(String[] args) {
        int i, n, L, R, li, ri, ans, rLimit, rMax;
        boolean flag;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextInt()) {
            ans = 0;
            array.clear();
            n = scanner.nextInt();
            L = scanner.nextInt();
            R = scanner.nextInt();
            for (i = 0;i < n;i++) {
                li = scanner.nextInt();
                ri = scanner.nextInt();
                if (ri < L || li > R) {
                    continue;
                }
                array.add(new Region(li, ri));
            }
            if (array.size() == 0) {
                System.out.println(-1);
                continue;
            }
            Collections.sort(array, new Comparator<Region>() {
                @Override
                public int compare(Region o1, Region o2) {
                    return o1.l - o2.l;
                }
            });
            rLimit = L;
            rMax = L;
            for (i = 0;i < array.size();i++) {
                flag = false;
                while (i < array.size() && array.get(i).l <= rLimit) {
                    rMax = Math.max(rMax, array.get(i).r);
                    i++;
                    flag = true;
                }
                if (flag) {
                    i--;
                    rLimit = rMax;
                    ans++;
                }
                if (rLimit >= R) {
                    break;
                }
            }
            System.out.println(rLimit >= R ? (ans == 0 ? -1 : ans) : -1);
        }
    }


}

class Region {
    public int l;
    public int r;

    public Region(int l, int r) {
        this.l = l;
        this.r = r;
    }
}

问题2:

在这里插入图片描述
在这里插入图片描述

思路:

  该题乍一看好像和区间没什么关系,但我们需要发现对于每个村庄(x,y),到其距离不超过D的出口的x坐标值处于一个区间内,该区间为[x - sqrt(d ^ 2 - y ^ 2),x + sqrt(d ^ 2 - y ^ 2)
  于是,这道题被转化为了区间贪心的问题。成为了区间贪心的一种:在满足每个区间中至少有一个点(出口)情况下,最少能选择多少个点(出口)?我们的贪心策略是使一个点(出口)尽可能多地处于不同区间内,即尽可能多的区间能共用一个点(出口)。
  如何执行上述贪心策略呢?我们可以按区间的右端点从小到大对区间排序,定义右极限rLimit,初值为第一个区间的右端点,然后进行区间的遍历。若当前遍历到的区间的左端点<=rLimit,说明当前区间可以和前面的某些区间共用一个点(这是因为当前区间和前面的某些区间都满足左端点<=rLimit,且由于排序关系,右端点>=rLimit,也就是说这些区间存在公共的重叠部分,可以共用一个出口),若当前遍历的区间左端点>rLimit,说明当前区间和前面的区间不可共用一个点,所需出口数ans++,并更新rLimit的值为当前区间的右端点,重复上述过程直到遍历完所有区间。

代码:

import java.util.*;

public class Main {
    static Region[] array = new Region[1002];
    public static void main(String[] args) {
        int ans, i, n;
        double l, d, x, y, left, right, nextLeft, nextRight;
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextDouble()) {
            ans = 0;
            l = scanner.nextDouble();
            d = scanner.nextDouble();
            n = scanner.nextInt();
            for (i = 0;i < n;i++) {
                x = scanner.nextDouble();
                y = scanner.nextDouble();
                left = x - Math.sqrt(d * d - y * y);
                right = x + Math.sqrt(d * d - y * y);
                left = left > 0 ? left : 0;
                right = right > l ? l : right;
                array[i] = new Region(left, right);
            }
            Arrays.sort(array, 0, n, new Comparator<Region>() {
                @Override
                public int compare(Region o1, Region o2) {
                    if (o1.right - o2.right > 0) {
                        return 1;
                    }
                    return -1;
                }
            });
            right = array[0].right;
            for (i = 0;i < n;i++) {
                nextLeft = array[i].left;
                nextRight = array[i].right;
                if (nextLeft > right) {
                    right = nextRight;
                    ans++;
                }
            }
            ans = n == 0 ? ans : ans + 1;
            System.out.println(ans);
        }
    }
}

class Region {
    public double left;
    public double right;

    public Region(double left, double right) {
        this.left = left;
        this.right = right;
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/153734.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!