当前位置:文档之家› 带期限的作业调度问题的算法与实现

带期限的作业调度问题的算法与实现

2010-2011 第二学期08通信专业期末考查带期限的作业调度问题的算法与实现班级08通信一班学号14082300939姓名XXXX成绩分一、设计目的1.掌握FIFO和LIFO宽度优先检索原理;2.掌握LC,FIFO分枝界限法;3.进一步掌握分枝界限法的基本思想和算法设计方法;二、设计内容1.任务描述(1)给定一个带期限的作业排序问题, n=5, (p1,p2,p3,p4,p5)=(6,3,4,8,5), (t1,t2,t3,t4,t5)=(2,1,2,1,1), (d1,d2,d3,d4,d5)= (3,1,4,2,4), 应用FIFOBB求使总罚款数最小的可行作业集J. 要求:( 2 )设计任务简介a)阐述c’(X)和u(X)的设计思路,U的初始值;b)针对解向量变长格式, 画出FIFOBB的生成的部分状态空间树, 按活节点生成顺序给节点编号,在各节点位置给出c’(X)和U的值,给每条边标记选择的作业编号;c)阐述c’(X)=U的处理方案, 可行解的判断方案;d)阐述你程序中的主要数据类型、数据变量和功能模块。

e)、编成并上机实现FIFOBB程序, 实现对不同作业排序问题实例的求解,问题实例的输入数据存储在case.txt文件中,其格式为:第一行问题规模(最多10个作业)第二行各作业的罚款数,数据项之间用一个空格分隔第三行各作业的截止期限,数据项之间用一个空格分隔第四行各作业所需的运行时间,数据项之间用一个空格分隔例如:45 106 31 32 11 2 1 1从屏幕直接输出最优作业集的序号,数据项之间用逗号分隔。

2.任务简答(1)阐述c’(X)和u(X)的设计思路,U的初始值;c’(X):为当前未选的作业的罚款数。

设计思路:定义一个估计罚款数c;用来记录当前估计数,当再有一个作业分配时,看分配过程中是否有损失的效益;如果有则将其损失值与父亲节点中的c相加记录在当前分配作业的节点c 中去;如果没有损失效益则当前的节点c还是为其父节点的c。

u(X):在当前所选作业中还有可能得到的罚款数的上限值。

设计思路:在计算估计罚款数时在计算当前已得到的罚款数与没有选的作业罚款数之和,同样是记录在节点中,用节点中u记录;每做一个作业时就将其父亲节点的u减去当前所做作业的得到的效益值。

即罚款数的上限不断缩小。

这样就可以用其来剪去不必要的树枝,也是FIFOBB算法的原理所在。

U的初始值:所有作业的效益值。

(2)针对解向量变长格式, 画出FIFOBB的生成的部分状态空间树, 按活节点生成顺序给节点编号,在各节点位置给出c’(X)和U的值,给每条边标记选择的作业编号;图.FIFOBB的生成的部分状态空间树(3)阐述c’(X)=U的处理方案, 可行解的判断方案;在这个问题上我给出对c’(x)=U的处理是:因为在这个问题中U一直都是是一个纯粹估计的上界, 保留满足c’(X) ≤ U 的活节点X所以当两者相等时,直接让此节点进队列。

可行解的判断方案:判断节点的c’(x)是否小于等于当前的U;如果是就判断为可行解,并进队列;如果大于U则为非可行解,不进队列。

3.主要数据类型与变量Typdef struct node{int time; //记录所选作业的总时间int parent;//记录节点的父亲节点int x; //记录所选的作业序号int u; //记录罚款上限int c; //估计罚款int date; //记录所选作业的最后截止期限}F;F q[30]; //定义队列结构体数据变量int i,j; //控制队列进出指针int max=1000;4.算法或程序模块void cost(int k,int E)/*估计成本函数*/void inter(int k,int E)/*进队列函数并缩小上限罚款成本*/ int ynset()/*判断队列是否为空函数*/int outQ()/*出队列函数*/void FIFOBB(int E,int t)/*分支限界算法求作业最优解函数*/ 三.测试2.方案在VC6.0环境下,运行;3.结果在E盘下写入case.txt;Case.txt45 106 31 32 11 2 1 1由图可知选2,3便可达到最优解。

当然也可以写入多组数据:如果在case.txt中写入以下二组数据:45 106 31 32 11 2 1 151 3 4 5 102 4 8 11 23 4 7 9 13由图可知,选4便可达到最优解。

四.总结与讨论本次实验增强了我们自主动手编程能力,我在本次编程过程中,犯的比较大的错误就是把S=0放到了while循环的外面,导致循环出了问题。

在for循环可能容易发现错误,但是在while 里面我经常弄错,这是以后要注意的。

这次实验主要是加深了我们对分枝限界法的理解,终于解决了以前我把它与回溯法的混淆问题。

其实分支限界法与回溯法是有很大不同的,其一,在求解目标上,回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。

基二,在搜索方式上,回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。

再有一点比较深的体会是,我觉得分枝界限法的关键是确定一个合理的限界函数。

本实验的设想:我们都知道分枝界限法是寻找结构主要失效模式的一种常用方法,但由于涉及到联合概率的计算而使过程相当繁琐。

我的设想是如果能够取消了限界操作,就可以大大简化了计算过程,具体方法目前没有想到,不过在网上看到有人提出用PNET法的思想引入到分枝限界法中,取消了限界操作的研究。

附:程序模块的源代码#include<stdio.h>typedef struct node{int time; //记录所选作业的总时间int parent; //记录节点的父亲节点int x; //记录所选的作业序号float u,c; //u,c分别记录罚款上限和估计罚款int date; //记录所选作业的最后截止期限}F;F q[30]; //队列结构体数组float p[10];int t[10],d[10],a[10]={0,1,2,3,4,5,6,7,8,9};int i,j,D,k,E,b;float co,up,max=1000,U,e=0.5;F w[1];int time(int k,int E)//判断当前所选作业时间是否冲突{if(q[E].date <d[a[k]])w[0].date =d[a[k]];else w[0].date =q[E].date;if(q[E].time+t[a[k]]>w[0].date )return 0;else return 1;}void cost(int k,int E)//计算估计成本函数{int m;if(!time(k,E))co=max;else if(q[E].x-a[k]!=-1){co=q[E].c;for(m=q[E].x+1;m<a[k];m++)co=co +p[m];}else co=q[E].c ;up=q[E].u -p[a[k]];}void enterq(int k,int E)//进队列的函数{q[j].c=co;q[j].date =d[a[k]];q[j].parent =E;q[j].time =q[E].time +t[a[k]];q[j].u =up;q[j].x =a[k];if(q[j].u <U){ U=q[j].u +e;b=j;}//记录答案节点j++;}int ynset()//判断队列是否为空{if(i!=j)return 0;else return 1;}int outq(){int t;t=i++;return t;}void FIFOBB(int E)//分枝限界函数{int t;while(!ynset()||i==1){for(k=q[E].x+1;k<D;k++){cost(k,E);if(co<U)//判断估计成本是否小于罚款上限,如果是则进队列;否则出队列enterq(k,E);}E=outq();}{ printf("最小罚款:%f",U-e);printf("\n");printf(" %d",q[b].x+1);printf("\n");t=q[b].parent;while(q[t].parent !=-1){printf(" %d",q[t].x+1 );printf("\n");t=q[t].parent;}}}void main()//主函数{int m;float s;freopen("E:\\case.txt","r",stdin);while(scanf("%d",&D)!=EOF&&D<=10) {s=0;for(m=0;m<D;m++){scanf("%f",&p[m]);s+=p[m]; }for(m=0;m<D;m++){scanf("%d",&d[m]);}for(m=0;m<D;m++){scanf("%d",&t[m]);}q[0].c =0;//初始化树的根节点q[0].u =s;q[0].date =0;q[0].time =0;q[0].parent =-1;q[0].x =-1;i=j=1;U=q[0].u +e;FIFOBB(0);}}。

相关主题