一、简单贪心
当题目中让我们最优的情况时,比如效益最大,组成的数最大等等,此时我们要想到贪心算法的思想。简单来说就是先去考虑局部最优,然后由局部最优组成全局的最优。比如,当求效益最大时,要达到效益最大,说明每个单独的个体的效益最大,所以我们可以先去求单价效益最大的情况开始;组成的数最大,那么就说明,每一个位放的数要最小,这也是局部最优,最后组成的数就是最小,达到了全局最优。
二、区间贪心(区间不相交问题与区间选点问题)
1.区间不相交问题
(1)问题描述:给出N个开区间,从中选择尽可能多的开区间,使得这些开区间两两没有交集
(2)解决问题的步骤:
①先定义一个结构体数组将区间全部存入
②对区间进行排序:按照左端点从大到小排序,如果左端点相同,则按照右端点从小到大排序,原因请看《算法笔记》P122
②然后遍历排好序的区间数组,选择第一个区间为标准,从第二个区间开始,如果该区间的右端点在选定的标准区间的左端点的左边,则更新标准区间为它,然后不相交的区间的数量+1
(3)代码如下:
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
class Inteval {
public int left,right;
Inteval(int a,int b) {
this.left = a;
this.right = b;
}
}
class cmp implements Comparator<Inteval>{
@Override
public int compare(Inteval o1,Inteval o2) {
if(o1.left!=o2.left){
return o1.left>o2.left?-1:1;//按照left降序排序
}
else{
return o1.right>o2.right?1:-1;//按照right升序排序
}
}
}
public class Test {
public static void main(String []args){
int n;
Scanner cin=new Scanner(System.in);
n=cin.nextInt();
Inteval []I=new Inteval[n+1];
for(int i=0;i<n;i++){
int left=cin.nextInt();
int right=cin.nextInt();
I[i]=new Inteval(left,right);//太容易错了,要先给数组中的每一个元素开辟一个空间,否则都是空的
}
Arrays.sort(I,0,n, new cmp());
for(int i=0;i<n;i++){
System.out.println(I[i].left+" "+I[i].right);
}
//ans用来记录不相关的区间的个数,lastX用来记录上一个被选中区间的左端点
int ans=1,lastX=I[0].left;
for(int i=1;i<n;i++){
if(I[i].right<=lastX){
ans++;
lastX=I[i].left;
}
}
System.out.println(ans);
}
}
(4) 知识点及易错点
①Java如何用Scanner进行连续输入
②Java如何自定义sort对类进行排序
③当建立一个类的数组时,对数组的元素进行复制的时候,要先给每一个元素先new,然后才可以赋值
以上的知识点都总结到了这个帖子上,详情请看:
https://blog.youkuaiyun.com/Warddamn/article/details/114269664
2.区间选点问题
(1)问题描述:给出N个闭区间,求最少需要确定多少个点,才能使每个闭区间中都至少存在一个点。
(2)解决问题的步骤:
①先定义一个结构体数组将区间全部存入
②对区间进行排序:按照左端点从大到小排序,如果左端点相同,则按照右端点从小到大排序,原因请看《算法笔记》胡凡版P122
②然后遍历排好序的区间数组,选择第一个区间为标准,从第二个区间开始,如果该区间的右端点在选定的标准区间的左端点的左边**(注意此时是不能带等号的)**,则更新标准区间为它,然后不相交的区间的数量+1
(3)代码实现
与1的代码完全一致,除了将小于等于改成小于,即如下:
if(I[i].right<lastX) {...}
原因请看《算法笔记》胡凡版P122
--------------------------------------------3.24 更新笔记--------------------------------------
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
/*
* 本节重新说明了比较器的问题,比较器
* compare(A a, A b)
* 当a-b的时候为升序排序,b-a的时候为降序排序
* 若a和b为字符串,则a.compareTo(b)的时候为升序排序,b.compareTo(a)为降序排序
* 因此,如果有特殊的对a=b有要求的话可以这么写
* Comparator<Greed> cmp=new Comparator<Greed>() {
public int compare(Greed a,Greed b) {
if(a.x!=b.x) {
return b.x-a.x;
}else {
return a.y-b.x;
}
}
};
* 如果没有的话,就可以直接这样
* Comparator<Greed> cmp=new Comparator<Greed>() {
public int compare(Greed a,Greed b) {
return a.x-b.x;//升序
}
};
* 详情可以看如下网站:
* https://lhf2018.github.io/2019/10/20/Java%E9%87%8D%E5%86%99%E6%AF%94%E8%BE%83%E5%99%A8/
*
*易错知识点:
*(1) 在主类中新建子类或者全局变量要加static。
*(2) 当建立一个新类子类时,要写构造函数。
*(3) 当建立一个新类数组的时候,要对数组中的每一个元素进行实例化。
*
*/
public class _区间贪心 {
static class Greed//新建类要设置构造函数,此外,在主类里面建立全局变量或者是子类的话一定要加static
{
int x=0;
int y=0;
Greed(){};
}
static Comparator<Greed> cmp=new Comparator<Greed>() {
public int compare(Greed a,Greed b) {
if(a.x!=b.x) {
return b.x-a.x;//降序排序
}else {
return a.y-b.y;
}
}
};
public static void main(String[] args) {
Scanner cin=new Scanner (System.in);
int n;n=cin.nextInt();
Greed []greed=new Greed[n];//新建了新类型的数组,一定要给每个元素初始化
for(int i=0;i<n;i++) {
greed[i]=new Greed();
greed[i].x=cin.nextInt();
greed[i].y=cin.nextInt();
}
//测试比较器
Arrays.sort(greed,cmp);
for(int i=0;i<n;i++) {
System.out.println(greed[i].x+","+greed[i].y);
}
//解决问题,下一个的右端点要小于等于当前这个的左端点
int count=1; Greed last=greed[0];
for(int i=1;i<n;i++) {
if(last.x>=greed[i].y) {
last=greed[i];
count++;
}
}
System.out.println(count);
}
}