前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >挑战程序竞赛系列(7):2.1一往直前!贪心法(区间)

挑战程序竞赛系列(7):2.1一往直前!贪心法(区间)

作者头像
用户1147447
发布2019-05-26 09:48:05
3630
发布2019-05-26 09:48:05
举报
文章被收录于专栏:机器学习入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1434774

挑战程序竞赛系列(7):2.1一往直前!贪心法

详细代码可以fork下Github上leetcode项目,不定期更新。

练习题如下:

  1. POJ 2376: Cleaning Shifts
  2. POJ 1328: Radar Installation
  3. POJ 3190: Stall Reservations

POJ 2376: Cleaning Shifts

思路:

贪心,先按开始时间排序,如刚开始begin = 1时,从大于begin的所有牛中选择end最大的,为下一轮的begin时间,这样一直继续下去,直到大于T即可。代码如下:

代码语言:javascript
复制
public class SolutionDay23_P2376 {

    private static class Pair{
        int s; 
        int e;
        Pair(int s, int e){
            this.s = s;
            this.e = e;
        }

        @Override
        public String toString() {
            return "["+s+","+e+"]";
        };
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int T = in.nextInt();
        Pair[] pairs = new Pair[N];
        for (int i = 0; i < N; i++){
            int s = in.nextInt();
            int e = in.nextInt();
            pairs[i] = new Pair(s,e);
        }
        System.out.println(solve(pairs,T));
        in.close();
    }

    private static int solve(Pair[] pairs, int T){
        Arrays.sort(pairs, new Comparator<Pair>() {
            @Override
            public int compare(Pair o1, Pair o2) {
                return o1.s != o2.s ? o1.s - o2.s : o1.e - o2.e ;
            }
        });

        int pos = 0;
        int end = 0;
        int step = 0;
        int begin = 0;
        while (end < T){
            begin = end + 1;
            for (int i = pos; i < pairs.length; i++){
                if (pairs[i].s <= begin){
                    end = Math.max(end, pairs[i].e);
                }else{
                    pos = i;
                    break;
                }
            }

            if (begin > end){
                return -1;
            }
            else{
                step ++;
            }
        }
        return step;
    }

}

POJ 1328: Radar Installation

思路:

刚开始的想法是根据岛屿的y坐标进行排序,然后每次选择最大的y值,以它的x为雷达中心,把所有覆盖的岛屿删除,再选择第二个雷达,依此类推,直到没有岛屿,WA了。其实想想也挺蠢的,你就那么确定雷达的中心一定是在某个岛屿的下方?确定雷达的横坐标显然不是一个有效的做法。(因为它可以是个范围)

所以,雷达既然是范围,我们就不可能从雷达的角度去思考该问题,反过来,我们可以根据岛屿求得雷达可在的区域列表,这样计算过后,只要尽可能的让这些区域列表重合即可。

根据岛屿所在的位置,计算与x轴相交的两个点,记为start和end,计算公式如下:

代码语言:javascript
复制
以岛屿为圆心,构造:
(x-x1)^2 + (y-y1)^2 = d^2;
令 y = 0;
所以有:
start = x - (d*d - y*y)
end = x + (d*d - y*y)

好了,知道了每个雷达可在的区域,我们就开始选择吧。目标:尽可能的让所有区域列表重合,所以我们从最左端的start开始,它会有一个end区间。现在遍历start小于end区间的所有区域,最小end区间,一旦某个start超过end,就增加一个雷达。代码如下:

代码语言:javascript
复制
public class SolutionDay24_P1328 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int id = 0;
        while (true){
            String[] info = in.nextLine().trim().split(" ");
            int n = Integer.parseInt(info[0]);
            int d = Integer.parseInt(info[1]);
            if (n == 0 && d == 0) break;
            int[][] islands = new int[n][2];
            for (int i = 0; i < n; i++){
                String[] pos = in.nextLine().trim().split(" ");
                islands[i][0] = Integer.parseInt(pos[0]);
                islands[i][1] = Integer.parseInt(pos[1]);
            }
            in.nextLine();
            System.out.println("Case "+(++id)+": "+solve(islands, d));
        }
        in.close();
    }

    private static class Section{
        double start;
        double end;
        Section(double start, double end){
            this.start = start;
            this.end = end;
        }
    }
    private static int solve(int[][] islands, int d){
        Section[] sections = new Section[islands.length];
        for (int i = 0; i < islands.length; i++){
            int x = islands[i][0];
            int y = islands[i][1];
            if (y > d) return -1;
            double sqrt = Math.sqrt(d*d-y*y);
            sections[i] = new Section(x-sqrt, x+sqrt);
        }
        Arrays.sort(sections, new Comparator<Section>() {
            @Override
            public int compare(Section o1, Section o2) {
            //强转会出错,注意这个地方
                return (o1.start != o2.start ? o1.start - o2.start : o1.end - o2.end) > 0 ? 1 : -1;
            }
        });

        double minEnd = -1 << 30;
        int step = 0;
        for (int i = 0; i < sections.length; i++){
            if(sections[i].start <= minEnd){
                minEnd = Math.min(minEnd, sections[i].end);
            }else{
                step ++;
                minEnd = sections[i].end;
            }
        }
        return step;
    }
}

POJ 3190: Stall Reservations

不得不吐槽下,POJ系统对JAVA的支持太弱了,优先队列的接口居然能编译错误,更别说支持Java 8的一些特性了。

还是一道区间如何选择的问题,贪心策略:

总是先安排A小的那头奶牛,所以先对A进行排序,接着就是尽可能的把每头奶牛放入stall中,最糟糕的情况就是所有奶牛的喝奶区间都重合,这必然需要安排大小为奶牛数的stall来满足它们。

所以,如果区间不重,那么我们就可以把奶牛放在一个stall中,但这应该怎么操作呢?

我的想法:

针对第一头奶牛,能够得到一个end区间,此时,遍历余下的n-1头奶牛,把start > end的奶牛给筛选出来,然后更新end区间,并且删除该奶牛,直至末尾。

若还有剩余的奶牛,则再建个stall,重复上述步骤,直到所有奶牛被安置完成。

这是最基本的求解思路,但缺点就是需要遍历O(k∗n)O(k*n)次,k为stall数,n为奶牛数。

在上述想法中,我们还少使用了一个性质,每次安排一头新牛进入stall时,一定选择stall中end最小的那个,因为end较大的更不可能给这头新牛,必然区间重合。所以每次,只需要判断peek的stall是否满足cow.start > stall.end,如果满足则加入stall,不满足则创建新的stall来放这头牛。(贪心在这)

代码如下:

代码语言:javascript
复制
public class SolutionDay23_P3190 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[][] cows = new int[n][2];
        for (int i = 0; i < n; i++){
            cows[i][0] = in.nextInt();
            cows[i][1] = in.nextInt();
        }
        solve(cows, n);
        in.close();
    }

    private static class MilkTime{
        int start;
        int end;
        int id;
        public MilkTime(int start, int end,int id) {
            this.start = start;
            this.end = end;
            this.id = id;
        }
    }

    private static class Stall{
        int end;
        int id;
        public Stall(int end, int id){
            this.end = end;
            this.id = id;
        }

        @Override
        public String toString() {
            return "[end: "+end+" id: "+id+"]";
        }
    }

    private static void solve(int[][] cows, int n){
        MilkTime[] milks = new MilkTime[n];
        for (int i = 0; i < n; i++){
            milks[i] = new MilkTime(cows[i][0], cows[i][1], i);
        }

        Arrays.sort(milks,new Comparator<MilkTime>() {
            @Override
            public int compare(MilkTime o1, MilkTime o2) {
                return o1.start -  o2.start;
            }
        });

        PriorityQueue<Stall> queue = new PriorityQueue<>(new Comparator<Stall>() {
            @Override
            public int compare(Stall o1, Stall o2) {
                return o1.end - o2.end;
            }
        });

        int[] result = new int[n];
        for (int i = 0; i < n; i++){
            if (i == 0){
                put(queue, milks[i], true, result);
                continue;
            }
            if (milks[i].start <= queue.peek().end){
                put(queue, milks[i], true, result);
            }else{
                put(queue, milks[i], false, result);
            }
        }
        System.out.println(queue.size());
        for (int i = 0; i < n; i++){
            System.out.println(result[i]);
        }
    }

    private static void put(PriorityQueue<Stall> queue, MilkTime cow, boolean isNew, int[] result){
        if(isNew){
            int id = queue.size() + 1;
            result[cow.id] = id;
            Stall stall = new Stall(cow.end, id);
            queue.offer(stall);
        }else{
            Stall stall = queue.poll();
            stall.end = cow.end;
            result[cow.id] = stall.id;
            queue.offer(stall);
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年05月24日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 挑战程序竞赛系列(7):2.1一往直前!贪心法
    • POJ 2376: Cleaning Shifts
      • POJ 1328: Radar Installation
        • POJ 3190: Stall Reservations
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档