算法知识点
活动安排问题是可以利用贪心算法求解的经典案例,该问题要求尽可能多的利用某一公共资源,使尽可能多的活动用上公共资源。本次活动安排以会议安排为例,讲解如何在有限的时间内安排更多场次的会议。
算法题目描述
某跨国公司总裁在某一天有多场会议可以参加,但当中有的会议时间是冲突的,但总裁希望能尽量参与更多场次的会议,请你为总裁规划一个最佳方案。
原始会议表:
会议号id | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
开始start | 3 | 1 | 5 | 2 | 5 | 3 | 8 | 6 | 8 | 12 |
结束end | 6 | 4 | 7 | 5 | 9 | 8 | 11 | 10 | 12 | 14 |
做题思路
对会议按结束时间排序
- 根据结束时间从早到晚排序
- 当结束时间相同时,按开始时间从晚到早排序
贪心策略
- 首先选择第一个最早结束的会议
- 记录当前会议结束时间last
- 依次从未安排会议中选取满足开始时间>=last的会议
- 如果会议开始时间>=last,会议相容,可安排,否则不可安排
- 遇到可安排的会议时,更新last
- 重复以上步骤,直到遍历完最后一个会议
由于进行了时间排序,所以在会议选择上,自需要考虑会议的开始时间是否>=上一个会议的结束时间last,如果会议开始时间>=last,那么说明两个会议不重合,这个会议可以被按安排进来,更新last为新加入会议的结束时间,然后接着往下找,直到遍历完排序后的会议数组
排序后的会议表
会议号id | 2 | 4 | 1 | 3 | 6 | 5 | 8 | 7 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
开始start | 1 | 2 | 3 | 5 | 3 | 5 | 6 | 8 | 8 | 12 |
结束end | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 |
贪心选择过程
会议号id | 2 | 4 | 1 | 3 | 6 | 5 | 8 | 7 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
开始start | 1 | 2 | 3 | 5 | 3 | 5 | 6 | 8 | 8 | 12 |
结束end | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 |
- 选取会议:2
- 结束时间 last = 4
会议号id | 2 | 4 | 1 | 3 | 6 | 5 | 8 | 7 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
开始start | 1 | 2 | 3 | 5 | 3 | 5 | 6 | 8 | 8 | 12 |
结束end | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 |
- 选取会议:2 - 3
- 结束时间 last = 7
会议号id | 2 | 4 | 1 | 3 | 6 | 5 | 8 | 7 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
开始start | 1 | 2 | 3 | 5 | 3 | 5 | 6 | 8 | 8 | 12 |
结束end | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 |
- 选取会议:2 - 3 - 7
- 结束时间 last = 11
会议号id | 2 | 4 | 1 | 3 | 6 | 5 | 8 | 7 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
开始start | 1 | 2 | 3 | 5 | 3 | 5 | 6 | 8 | 8 | 12 |
结束end | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 |
- 选取会议:2 - 3 - 7 - 10
- 结束时间 last = 14
遍历完排序后的会议数组,算法到此结束,得到的最优会议安排为:2 - 3 - 7 - 10
,共 4 个会议。
模板代码
import java.util.Arrays;
import java.util.Comparator;
public class MeetArrangement {
public static void main(String[] args) {
//这里是顺序排列的会议1、2、3、4、5、6、7、8、9、10
int[] start = {3,1,5,2,5,3,8,6,8,12};
int[] end = {6,4,7,5,9,8,11,10,12,14};
System.out.println(new MeetArrangement().meetArrangement(start,end));
}
//会议类,将每一个会议信息封装成对象
class Meet{
private int id;
private int start;
private int end;
public Meet(int id, int start, int end) {
this.id = id;
this.start = start;
this.end = end;
}
}
//核心方法,结果以会议号的字符串返回
public String meetArrangement(int[] start, int[] end){
String result = "";
Meet[] meetArr = new Meet[start.length];
//每一个会议信息封装成对象
for(int i=0;i<end.length;i++){
Meet m = new Meet(i+1,start[i],end[i]);
meetArr[i]=m;
}
//排序:Comparator比较器用于实现对象的排序
Arrays.sort(meetArr, new Comparator<Meet>() {
@Override
public int compare(Meet o1, Meet o2) {
//排序规则1:结束时间相等,开始时间慢的排前面
if(o1.end==o2.end){
return o2.start-o1.start;
}
//排序规则2:结束时间不相等,结束时间早的排前面
return o1.end-o2.end;
}
});
//贪心选择过程
//初始化,第一个会议直接添加,结束时间为当前last
result +=meetArr[0].id;
int last=meetArr[0].end;
for(int i=1;i<meetArr.length;i++){
if(meetArr[i].start>=last){
result = result+"-"+meetArr[i].id;
last = meetArr[i].end;
}
}
return result;
}
}
//输出结果:2-3-7-10
【注:文章部分内容参考自《趣学算法》】