前言:
目光长远的人学不了贪心算法?可恶可恶可恶,贪心果然是玄学!!!
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解 。
什么乱七八糟的,感觉贪心就是猜想加证明!说到这里,我想起了高中数学老师经常说的一句话,大胆猜想,小心求证!
贪心算法最常用的数据结构就是优先队列!!!
1.区间问题
题目链接:
1.区间合并
给定 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.区间选点
题目:
给定 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.管道--蓝桥杯真题练习
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.最大开支-蓝桥杯真题
哎呀这个题以后再写!可恶!