1.问题描述
输入: 活动的数量,以及每个活动的开始时间和结束时间
输出:最大相容活动集合的序列,以及开始时间和结束时间
2.实验目的
通过活动安排问题理解贪心选择思想,掌握活动安排问题的算法并通过编程练习加深理解。
3.实验原理
设有n个活动的集合E={1,2,3,…,n},其中每个活动都要求使用同一资源,每个活动都有一个使用该资源的开始时间Si和结束时间Fi,且Si<Fi。当Si≧Fj或者Sj≧Fi时活动i与活动j相容。
4.实验设计
private static void greedySelector(int n, int[] s, int[] f, boolean[] A) {
A[0]=true;//第一个活动被选中
int j=0;
for(int i=1;i<=n;i++){
if(s[i]>f[j]){//下一个活动的开始时间大于等于上一个活动的结束时间就可以选
A[i]=true;
j=i;
}else{//否则就不选
A[i]=false;
}
}
}
5.实验结果与分析
贪心算法并不是总能求得问题的整体最优解,但是对于活动安排问题,贪心算法却总能求得问题的整体最优解。关键在于对活动按结束时间进行了升序排列,所以每次选择的都是结束时间最早的,以达到尽可能多的安排活动,这体现了贪心选择性质。
6.结论
活动安排问题是可以用贪心算法求解的很好的例子,它能够很好的反映贪心算法的思想,要运用贪心选择算法需要问题具有最优子结构性质和贪心选择性质。
public class Greedy {
private static int lastEnd;
public static void main(String[] args) {
List<Action> list = new ArrayList<>();
@SuppressWarnings("resource")
Scanner sc = new Scanner(System.in);
System.out.println("请输入活动的数量:");
int x = sc.nextInt();
for(int i=1;i<=x;i++){
System.out.println("请输入第"+i+"活动的开始时间:");
int start = sc.nextInt();
System.out.println("请输入第"+i+"个活动的结束时间:");
int end = sc.nextInt();
Action action =new Action();
action.setStart(start);
action.setEnd(end);
list.add(action);
}
// list.add(new Action(2, 5));
// list.add(new Action(3, 7));
// list.add(new Action(1, 6));
// list.add(new Action(11, 20));
// list.add(new Action(8, 9));
// list.add(new Action(0, 3));
List<Action> actions = new ArrayList<>();
int minNum = 0;
int min = list.get(0).getStart();
//拿到所有活动中,开始时间最早的那一个
for (int i = 1; i < list.size(); i++) {
int as = list.get(i).getStart();
if (as < min)
minNum = i;
}
//第一个活动
Action firstAction = list.get(minNum);
firstAction.setCheck(true);
lastEnd = firstAction.getEnd();
//添加到集合
actions.add(firstAction);
list.remove(firstAction);
Action nextAction;
while ((nextAction = nextAction(list)) !=null) {
nextAction.setCheck(true);
lastEnd = nextAction.getEnd();
actions.add(nextAction);
list.remove(nextAction);
}
for (Action action : actions) {
System.out.println("action =" + action.toString());
}
System.out.println("-------------------------------------------------");
if (list.size() > 0) {
for (Action a : list) {
System.out.println("action =" + a.toString());
}
}
}
private static Action nextAction(List<Action> list) {
int size = list.size();
int minInt = -1;
int minNumber = -1;
int[] ss = new int[size];
for (int h = 0; h < size; h++) {
//赋初值,唔 。。。这里应该可以改一下
ss[h] = -1;
}
//计算集合中活动的开始时间和存储的上一次活动的结束时间的差值
for (int i = 0; i < size; i++) {
Action action = list.get(i);
int start = action.getStart();
if (start >= lastEnd) {
ss[i] = start - lastEnd;
}
}
//差值最小的就是下一个活动
for (int m = 0; m < size; m++) {
int s = ss[m];
if (s != -1) {
if (minInt == -1) {
minInt = s;
minNumber = m;
} else {
if (s < minInt) {
minNumber = m;
}
}
}
}
if (minNumber != -1) {
return list.get(minNumber);
}
return null;
}
}
public class Action {
private int start;
private int end;
private boolean isCheck = false;
public Action() {
super();
}
public Action(int start, int end) {
super();
this.start = start;
this.end = end;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public boolean isCheck() {
return isCheck;
}
public void setCheck(boolean check) {
isCheck = check;
}
@Override
public String toString() {
return "Action{" +
"start=" + start +
", end=" + end +
", isCheck=" + isCheck + '}';
}
}