您的位置:首页 > 其它

动态规划与贪心算法之课程安排问题

2016-10-10 23:14 453 查看

动态规划算法与贪心算法之课程安排问题

动态规划算法之课程安排

问题:教务处给某一个教室安排课程,有很多老师都想来这个教室教授他们各自的课。假如第i位老师讲的第Ai门课程,课程开始时间Si,结束时间为Fi。那么教务处的老师就要利用这个时间如何安排课程,使得来这间教室上课的人数最多?

举个例子:



最底下为时间轴,每条黑线代表一门课程。我们用W表示该课程有多少学生。我们看教务处安排最多有多少人来该教室上课。

分析:课程太多我无从下手。看能不能分成子问题求解。先DandC,然后DP。我们把求解过程看出一系列决策过程,在每个步骤我们都要选一门课程。假装我们已经拿到了最优决策方案,我现在就想知道最优解中最后一个决策到底是什么?也就是An 你是选了还是木有选?假如选择了,那A8 肯定不能选。为啥,时间冲突啦。那剩下的问题就是从其他几门课选最优的。如下图所示:



也就是说我们选择了一门课程之后,问题规约成一个7门课程安排问题,这样我们继续往下把问题变小。此外我们刚才是选啦A9,要是我们刚刚没选A9,那怎么办呢?显然从其他8门课程选择,不管时间是否冲突。如下图所示:



这里插一句非常关键话:我们一开始把课程按结束时间排好序。

现在我们就可以写出递归表达式了:

OPT(n)=max⎧⎩⎨ OPT(pre(i))+WiOPT(i−1)此处,其中pre(i)是表示第i门课程开始时已经结束的课程。

具体实现过程如下:

#include<stdio.h>
struct course{
float start;
float end;
int w;
}Course[9];
void init_course_information(){
Course[0].start =8;Course[0].end=9;Course[0].w=1;
Course[1].start=8;Course[1].end=9.30;Course[1].w= 5;
Course[2].start =9.20;Course[2].end     =10;Course[2].w=4;
Course[3].start =9.40;Course[3].end =10.30;Course[3].w=2;
Course[4].start =11.00;Course[4].end =12.30;Course[4].w=3;
Course[5].start =8;Course[5].end =12.50;Course[5].w=2;
Course[6].start =11.30;Course[6].end =13.00;Course[6].w=1;
Course[7].start =15;Course[7].end =16;Course[7].w=3;
Course[8].start =14;Course[8].end =17;Course[8].w=5;
}
int max(int a,int b){
return a>b?a:b;
}
int pre(int n){//求课程n开始时结束的所有课程
float current_start;
int result=0,i;
current_start=Course
.start;
for(i=0;i<8;i++){
if(Course[i].end>current_start){
result=i-1;
break;
}
}
return result;
}
int  Scheduling_DP(int n){
int m=0;
if(n<0)
return 0;
else if(n==0){
return Course[0].w;
}
else{
m=max( (Scheduling_DP(pre(n))+Course
.w ),  Scheduling_DP(n-1) );
return m;
}
}
void main(){
int i,result;
int n=9;//课程数量
init_course_information();
printf("         开始时间  结束时间  上课人数:\n");
for(i=0;i<9;i++)
printf("课程%d:%6.2f%8.2f%9d\n", i, Course[i]. start,Course[i]. end,Course[i].w);
result=Scheduling_DP(n-1);
printf("最多上课人数=%d\n",result);
}


运行结果如下:



2. 贪心算法之课程安排问题:

问题:现在我们假设每个课程的人数都为1。我们的任务还是和原来一样,选择一些不冲突的课程,让来该教室上课的学生人数最多,怎么办?当然上面的动态算法我们可以继续使用。但DP来解决这个问题就感觉有点慢了。为啥?还有更快的算法?问题如下图所示:



分析: 我们来审视这个问题。原来的性质依然存在。而且还多了个性质,那就是贪心选择的性质。它又是什么呢?回到问题本身,可以这么描述,假如课程Ai 下课最早,那么它肯定会出现在最优解。首先我们选最早下课的课程A1,接下来的问题就是在蓝色的方框里面选最优解就行,如此规约。



这个时候,我们写出递归表达式如下:

OPT(n)=max⎧⎩⎨ OPT(pre(i))+WiOPT(i−1)此处,其中pre(i)是表示第i门课程开始时已经结束的课程。

具体实现过程如下:

#include<stdio.h>
struct course{
float start;
float end;
int w;
}Course[9];
void init_Course_information(){
Course[0].start =8;Course[0].end =9;Course[0].w=1;
Course[1].start =8;Course[1].end =9.30;Course[1].w=1;
Course[2].start =9.20;Course[2].end =10;Course[2].w=1;
Course[3].start =9.40;Course[3].end =10.30;Course[3].w=1;
Course[4].start =11.00;Course[4].end =12.30;Course[4].w=1;
Course[5].start =8;Course[5].end =12.50;Course[5].w=1;
Course[6].start =11.30;Course[6].end =13.00;Course[6].w=1;
Course[7].start =15;Course[7].end =16;Course[7].w=1;
Course[8].start =14;Course[8].end =17;Course[8].w=1;

}
int  Scheduling_Greedy(int n){
int previous_finish_time=0;
int num=0;
int i;
for(i=0;i<9;i++){
if(Course[i].start>previous_finish_time){
previous_finish_time=Course[i].end;
num+=1;
}
}
return num;
}
void main(){
int i,result;
int n=9;//课程数量
init_Course_information();
printf("         开始时间  结束时间  上课人数:\n");
for(i=0;i<9;i++){
printf("程%d:%6.2f%8.2f%9d\n",i,Course[i].start,Course[i].end,Course[i].w);
}
result=Scheduling_Greedy(n-1);
printf("最多上课人数=%d\n",result);
}


总结:动态规划算法和贪心算法都是用来求解优化问题。最优子结构性质二者都要用到,但是贪心算法还要用到贪心性质,这个不同问题,贪心性质不同。此外,每个贪心算法的背后几乎都有一个动态规划算法。上面的这两个问题都可用动态规划求解。但第一个问题却不能用贪心算法求解。动态规划算法需要在每一个决策步枚举所有的解空间中的解,而贪心算法不需要,依赖局部最优解来做决策。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: