算法基础课贪心部分每道题贪心策略的证明汇总 - AcWing
1.区间问题
905. 区间选点 - AcWing题库
1.将每个区间按右端点从小到大排序
2.从前往后依次枚举每个区间,如果当前区间中已经包含点,则直接pass,否则,选择当前区间的右端点
使每一个选出来的右端点尽可能的占更多的空间
import java.util.*;
class Range implements Comparable<Range>{//定义一个新的结构体
int l, r;
public Range(int l, int r){
this.l = l;
this.r = r;
}
public int compareTo(Range o){
return Integer.compare(r, o.r);//根据右端点的大小排序
}
}
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = 100010;
int INF = 0x3f3f3f3f;
Range[] range = new Range[N];//定义一个结构体类型的数组
int n = sc.nextInt();
for(int i = 0; i < n; i ++){
int l = sc.nextInt();
int r = sc.nextInt();
range[i] = new Range(l, r);
}
Arrays.sort(range, 0, n);//排序
int res = 0;//共需要多少个点
int ed = -INF;//表示上一个区间的右端点
for(int i = 0; i < n; i ++){
if(ed < range[i].l){
res ++;
ed = range[i].r;
}
}
System.out.print(res);
}
}
908. 最大不相交区间数量 - AcWing题库
1.将每个区间按右端点从小到大排序
2.从前往后依次枚举每个区间,如果当前区间中已经包含点,则直接pass,否则,选择当前区间的右端点
除了问法不一样,和上一题本质上是一样的
import java.util.*;
//和上一题的代码一样
class Range implements Comparable<Range>{
int l, r;
public Range(int l, int r){
this.r = r;
this.l = l;
}
public int compareTo(Range o){
return Integer.compare(r, o.r);
}
}
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = 100010, INF = 0x3f3f3f3f;
Range[] range = new Range[N];
int n = sc.nextInt();
for(int i = 0; i < n; i ++){
int l = sc.nextInt();
int r = sc.nextInt();
range[i] = new Range(l, r);
}
Arrays.sort(range, 0, n);
int res = 0;
int ed = -INF;
for(int i = 0; i < n; i ++){
if(ed < range[i].l){
res ++;
ed = range[i].r;
}
}
System.out.print(res);
}
}
906. 区间分组 - AcWing题库
1.将每个区间按左端点从小到大排序
2.从前往后处理每个区间,判断能否将其放到某个现有的组中(L[i] > Max_r)
如果不存在这样的组,则开新组,将其放进去
如果存在这样的组,将其放进去,并更新当前组的Max_r
import java.util.*;
class Range implements Comparable<Range>{
int l, r;
public Range(int l, int r){
this.l = l;
this.r = r;
}
public int compareTo(Range o){
return Integer.compare(l, o.l);
}
}
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = 100010;
Range[] range = new Range[N];
int n = sc.nextInt();
for(int i = 0; i < n; i ++){
int l = sc.nextInt();
int r = sc.nextInt();
range[i] = new Range(l, r);
}
Arrays.sort(range, 0, n);//根据左端点排序
Queue<Integer> heap = new PriorityQueue<>();//小根堆
for(int i = 0; i < n; i ++){
if(heap.isEmpty() || range[i].l <= heap.peek()) heap.add(range[i].r);//建立一个新的组
else{
heap.poll();
heap.add(range[i].r);
}
}
System.out.print(heap.size());
}
}
907. 区间覆盖 - AcWing题库
1.将所有区间按照左端点从小到大排序
2.从前往后依次枚举每个区间,在所有能覆盖start的区间中,选择右端点最长的,并将start更新为右端点的最大值
import java.util.*;
class Range implements Comparable<Range>{
int l, r;
public Range(int l, int r){
this.l = l;
this.r = r;
}
public int compareTo(Range o){
return Integer.compare(l, o.l);
}
}
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int st = sc.nextInt();
int ed = sc.nextInt();
int n = sc.nextInt();
int N = 100010;
Range[] range = new Range[N];
for(int i = 0; i < n; i ++){
int l = sc.nextInt();
int r = sc.nextInt();
range[i] = new Range(l, r);
}
Arrays.sort(range, 0, n);
int res = 0;
boolean flag = false;
for(int i = 0; i < n; i ++){
int j = i;
int r = -0x3f3f3f3f;
while(j < n && range[j].l <= st){//一定要注意条件的顺序问题
r = Math.max(r, range[j].r);//找到覆盖st的区间中右端点最长的
j ++;
}
if(r < st){//如果循环到最后都没能超过st,则res=-1
res = -1;
break;
}
res ++;//否则区间数量加1
if(r >= ed){
flag = true;//如果最右端点已经超过ed,那么就直接结束循环
break;
}
st = r;//把最右端点赋值给新的st
i = j - 1;
}
if(!flag) res = -1;
System.out.print(res);
}
}
2.哈夫曼树
148. 合并果子 - AcWing题库
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
Queue<Integer> heap = new PriorityQueue<>();//建立一个小根堆
int n = sc.nextInt();
while(n -- > 0){
int x = sc.nextInt();
heap.add(x);
}
int res = 0;
while(heap.size() > 1){
int a = heap.peek();//取出两个最小的数
heap.poll();
int b = heap.peek();
heap.poll();
res += a + b;
heap.add(a + b);
}
System.out.print(res);
}
}