蓝桥杯之贪心算法

前言:

目光长远的人学不了贪心算法?可恶可恶可恶,贪心果然是玄学!!!

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解 。

什么乱七八糟的,感觉贪心就是猜想加证明!说到这里,我想起了高中数学老师经常说的一句话,大胆猜想,小心求证!

贪心算法最常用的数据结构就是优先队列!!!

1.区间问题

题目链接:

1.区间合并

803. 区间合并 - AcWing题库

给定 n 个区间 [l,r],要求合并所有有交集的区间。

输出合并后的区间个数。

贪心思路:

将区间按左端点排序,从前往后依次枚举每个区间,维护一个区间,判断接下来的区间与它是否有交集;

自己画一个图之后就很好理解:维护排序后的第一个区间,如果下一个区间的左端点大于当前区间的右端点,说明两个区间没有交集。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class Main {
    static ArrayList<Rangle>list=new ArrayList<>();
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        while(n--!=0){
            int l=sc.nextInt();
            int r=sc.nextInt();
            list.add(new Rangle(l,r));
        }
        Collections.sort(list);
        int st=list.get(0).l;
        int ed=list.get(0).r;
        ArrayList<Rangle>res=new ArrayList<>();
        res.add(new Rangle(st,ed));
        for (int i = 1; i < list.size(); i++) {
            if(list.get(i).l>ed){
                res.add(new Rangle(list.get(i).l,list.get(i).r));
                st=list.get(i).l;
                ed=list.get(i).r;
            }else {
                 ed=Math.max(ed,list.get(i).r);
            }
        }

        System.out.println(res.size());

    }
    static class Rangle implements Comparable<Rangle>{
        int l;
        int r;

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

        @Override
        public int compareTo(Rangle o) {
            return this.l-o.l;
        }
    }
}

2.区间选点

905. 区间选点 - AcWing题库

题目:

给定 N 个闭区间,请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。

输出选择的点的最小数量。

位于区间端点上的点也算作区间内。

有人说这不是和区间合并一样吗?Nonononono!!!当然不一样了,区间合并要维护的区间不一定与其他的所有区间都有交集哦!!!

贪心思想:

将区间按右端点排序,维护第一个区间,从小到大依次枚举每个区间,要选的点尽可能的往右(即右端点)

如果枚举的区间包含该点,pass

如果不包含,res++,并将维护的区间改成当前区间;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class Main {
    static ArrayList<Rangle>list=new ArrayList<>();

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        while(n--!=0){
            int l=sc.nextInt();
            int r=sc.nextInt();
            list.add(new Rangle(l,r));
        }
        Collections.sort(list);
        int st=list.get(0).l;
        int ed=list.get(0).r;
        int res=1;

        for (int i = 1; i < list.size(); i++) {
            if(list.get(i).l<=ed){
                continue;
            }else{
                res++;
                ed=list.get(i).r;
            }
        }
        System.out.println(res);

    }



    static class Rangle implements Comparable<Rangle>{
        int l;
        int r;

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

        @Override
        public int compareTo(Rangle o) {
            return this.r-o.r;
        }
    }
}

3.最大不相交区间数量

给定 N 个闭区间,请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

输出可选取区间的最大数量。

第2题的本质就是这个意思,两题的代码完全一样,不多说。

4.区间分组

给定 N个闭区间,请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

输出可选取区间的最大数量。

5.管道--蓝桥杯真题练习

链接---4.管道 - 蓝桥云课 (lanqiao.cn)

2.哈夫曼树

经典问题,相信大家在数据结构的课上都学过这个问题,但那个时候我们好像还注意不到那是个贪心算法。

贪心思想:在构造哈夫曼树的时候,叶子节点被加的次数与路径长度有关(从根节点到叶子节点的路径),要保证WPL最小,我们肯定要让小的数被加的次数多一点,大的数被加的次数少一点。

因此我们可以选择两个较小的值依次合并!!!

优先队列,优先队列!!!

import java.util.PriorityQueue;
import java.util.Scanner;

public class 哈夫曼树 {
    static int sum;
    public static void main(String[] args) {
        PriorityQueue<Integer>pq=new PriorityQueue<>();
        Scanner sc=new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 0; i< n ; i++) {
            pq.offer(sc.nextInt());
        }

        while(pq.size()!=1){
            int top1=pq.poll();
            int top2=pq.poll();
            sum+=top1+top2;
            pq.offer(top1+top2);
        }
        System.out.println(sum);

    }

}

3.排队打水

有 n个人排队到 11 个水龙头处打水,第 i个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?

果然贪心来源于生活,有的时候我们都不知道我们用了贪心,就比如你打饭的时候,肯定是你前面的人打饭时间越短你越开心啊!!!话不多说,上代码!


import java.util.Arrays;
import java.util.Scanner;

public class 排队打水 {
    static int N=100010;
    static long[]a=new long[N];
    static long[]s=new long[N];
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 1; i<=n ; i++) {
           a[i]=sc.nextLong();
        }
        Arrays.sort(a,1,n+1);
         long sum=0;
        for (int i = 1; i <=n; i++) {
            s[i]=s[i-1]+a[i];
        }
        for (int i = 2; i <=n ; i++) {
            sum+=s[i-1];
        }
        System.out.println(sum);

    }
}

4.排序不等式

在一条数轴上有 N 家商店,它们的坐标分别为 A1∼AN。

现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。

为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。

贪心:我们可以从两家商店考虑,很明显建在它们之间最短为两家商店的距离,其他位置都比这个长;那三家商店呢,我们肯定建在中间最短!实际上证明是一个绝对值不等式问题:当x为何值时,使得|x-a|+|x-b|的值最小。

学过数学的我们都知道x在a,b之间,扩展到多维,依然有这个性质!!


import java.util.Arrays;
import java.util.Scanner;

public class 货仓选址 {
    static int N=100010;
    static int A[]=new int[N];

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 1; i<=n ; i++) {
            A[i]=sc.nextInt();
        }
        Arrays.sort(A,1,n+1);

        int mid=A[n/2],res=0;
        for (int i = 1; i <=n ; i++) {
            res+=Math.abs(A[i]-mid);
        }

        System.out.println(res);
    }
}

5.最大开支-蓝桥杯真题

哎呀这个题以后再写!可恶!

  • 21
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值