贪心算法
贪心算法是指在一个问题当中每一步的求解过程当中要求的是最优解,即贪婪的去寻求答案,并且希望通过一系列的最优解去得到整个问题的解决最优解
贪心算法每一步必须满足一下条件:
1、可行的:即它必须满足问题的约束。
2、局部最优:他是当前步骤中所有可行选择中最佳的局部选择。
3、不可取消:即选择一旦做出,在算法的后面步骤就不可改变了。
贪心算法案例
有n个在同一天使用同一个教室的a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。
用贪心法的话思想很简单:活动越早结束,剩余的时间是不是越多?那我就早最早结束的那个活动,找到后在剩下的活动中再找最早结束的不就得了?
虽然贪心算法的思想简单,但是贪心法不保证能得到问题的最优解,如果得不到最优解,那就不是我们想要的东西了,所以我们现在要证明的是在这个问题中,用贪心法能得到最优解。
代码奉上:
public class Main {
public static void main(String[] args) {
//创建活动并添加到集合中
Activt act1 = new Activt(1, 4);
Activt act2 = new Activt(3, 5);
Activt act3 = new Activt(0, 6);
Activt act4 = new Activt(5, 7);
Activt act5 = new Activt(3, 8);
Activt act6 = new Activt(5, 9);
Activt act7 = new Activt(6, 10);
Activt act8 = new Activt(8, 11);
Activt act9 = new Activt(8, 12);
Activt act10 = new Activt(2, 13);
Activt act11 = new Activt(12, 14);
List<Activt> Activts = new ArrayList<Activt>();
Activts.add(act1);
Activts.add(act2);
Activts.add(act3);
Activts.add(act4);
Activts.add(act5);
Activts.add(act6);
Activts.add(act7);
Activts.add(act8);
Activts.add(act9);
Activts.add(act10);
Activts.add(act11);
List<Activt> bestActivts = getBestActivts(Activts, 0, 16);
for (int i = 0; i < bestActivts.size(); i++) {
System.out.println(bestActivts.get(i));
}
}
/**
* @param activts 活动集合
* @param startTime 教室的开始使用时间
* @param endTime 教室的结束使用时间
* @return
*/
public static List<Activt> getBestActivts(List<Activt> activts, int startTime, int endTime) {
//最佳活动选择集合
List<Activt> bestActivts = new ArrayList<Activt>();
//将活动按照最早结束时间排序
Collections.sort(activts);
// activts.sort(new Activt());
//nowTime 用来记录上次活动结束时间
int nowTime = startTime;
/**
* 因为我们已经按照最早结束时间排序,那么只要活动在时间范围内
* Activts.get(1)就应当是第一个活动的结束时间.
* 则我们记录第一次活动结束的时间,在结合剩下的活动中,
* 选取开始时间大于nowTime且结束时间又在范围内的活动,则为第二次活动时间,
* 知道选出所有活动
*/
for (int i = 0; i < activts.size(); i++) {
Activt act = activts.get(i);
if (act.getStTime() >= nowTime && act.getEndTime() <= endTime) {
bestActivts.add(act);
nowTime = act.getEndTime();
}
}
return bestActivts;
}
}
public class Activt implements Comparable<Activt> {
private int stTime;
private int endTime;
public Activt(int stTime, int endTime) {
this.stTime = stTime;
this.endTime = endTime;
}
public int getStTime() {
return stTime;
}
public void setStTime(int stTime) {
this.stTime = stTime;
}
public int getEndTime() {
return endTime;
}
public void setEndTime(int endTime) {
this.endTime = endTime;
}
public int compareTo(Activt act) {
if (this.getEndTime() > act.getEndTime()) {
return 1;
}
if (this.getEndTime() < act.getEndTime()) {
return -1;
}
return 0;
}
@Override
public String toString() {
return "Activt{" +
"stTime=" + stTime +
", endTime=" + endTime +
'}';
}
}
打印结果:
Activt{stTime=1, endTime=4}
Activt{stTime=5, endTime=7}
Activt{stTime=8, endTime=11}
Activt{stTime=12, endTime=14}
于是我们可以看出,有些情况,贪心算法确实可以给出最优解,然而,还有一些问题并不是这种情况。对于这种情况,我们关心的是近似解,或者只能满足于近似解,贪心算法也是有价值的。