最优化方法课程大作业实验-流水线问题[元启发及超启发算法]
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
流水线调度问题求解
XXX (学号: XXXXXXXX)
摘要: 有N个工件同时到达流水线上,给出一个加工顺序排列使得最后一个工件从流水线最后一台机器加工完成所使用总时间最小。本实验将使用遗传算法作为主体框架,使用元启发与超启发算法对该问题进行优化求解。关键词: flow shop 多机调度遗传算法元启发式算法超启发式算法
1 引言
a) 流水车间(Flow Shop )调度问题是很多实际流水线生产调度问题的简化模型,也是一个典型的NP-hard 问题,因此其研究具有重要的理论意义和工程价值,也是目前研究最广泛的一类典型调度问题。
b) 已知:有n 个工件需要在m台机器上流水加工。
工件上的约束:所有工件均在0时刻释放且在各机器上的加工顺序相同,每个工件在每台机器上只加工一次。
机器上的约束:每个机器某一个时刻最多只能加工一个工件,而且执行过程是非抢占的。
目标:给出调度方案,使调度总完工时间最小。
要求:算法复杂度在多项式时间内。
c) 对于工件加工顺序的排列,可以看成是一段DNA序列,这段DNA序列可以交换片段的位置,可以改变两个碱基对的位置,分别对应基因的交叉与突变。而给所有排列(基因)一个生存空间,并定期淘汰掉不适应环境(总时间较大的个体),并让基因优良的排列进行繁殖。不断迭代,经过很多代的选择后,遗传下来的基因一定是更优的。
本文后续部分组织如下。第2节详细陈述使用的方法,第3节报告实验结果,第4节对讨论本文的方法并总结全文。
2 算法设计
遗传算法
对于流水线问题,遗传算法相比于其他群智能算法能更加贴近问题,更容易实现,因此我采用了遗传算法对该问题进行求解。具体设计思路如下:
遗传算法就是模拟了自然界中物竞天择,适者生存的法则,通过生物的不断变异和自然选择,遗传留下优秀的基因,淘汰不适应选择条件的基因。
对于工件加工顺序的排列,可以看成是一段DNA序列,第i个碱基对上的编码c表示第i个加工第c个工件。每个排列可看成一个细菌。在程序中,我使用一条链表来表示一个DNA链。这段
DNA序列可以交换片段的位置,可以改变两个碱基对的位置,分别对应基因的交叉与突变。繁殖
相当于复制链表并对链表进行交叉互换与碱基对互换。使用链表表示为片段与碱基的交换提供了
方便。给一个细菌一个生存空间,在初始阶段,细菌会大量地繁殖而导致数量呈指数型地增长。
程序通过随机或贪心生成一条初始的排列,每过一段时间完成一轮繁殖。当链的数量小于生存容
量时,DNA链的每一轮、每一个都会繁殖一条新的链,因此链的数量呈现指数型增长。当数量大
于生存空间的容量时,则需要淘汰一些劣质的DNA链。淘汰规则有轮盘赌、锦标赛等等,轮盘赌
即解更优的留下的概率更大,弱者也有概率留下,而锦标赛是严格的适者生存,留下的都是时间
较小的,这里我使用的是锦标赛规则。对总时间进行排序,杀死并销毁排名在生存榜上排名较后
2
的DNA链。并让留下来的DNA链进行下一轮繁殖与竞争。不断迭代,经过很多代的演化后,遗传下来的基因一定是更优的。
主要代码如下:
struct geneNode{ //碱基对,相当于脱氧核苷酸,形成链表
int p; //编码,指向的工件号
struct geneNode*next; //指向下一个碱基对
};
GeneNode*createNode(); //新建一个碱基对
class Gene{ //每一个基因即生存的个体
private:
GeneNode*head; //基因的第一个节点
int TotalTime; //花费的总时间
public:
Gene(); //初始化的构造函数
Gene(const Gene&b); //拷贝构造函数
Gene(GeneNode*dna); //为dna链构造对象
Gene(Gene b,int flag); //相当于复制一个b(链是新链,flag 无意义) 复制
~Gene(); //析构函数死亡
int calculateTotalTime(); //计算总时间
GeneNode*copyDNA(GeneNode*p); //复制DNA链
void deleteDNA(GeneNode*p); //删除并销毁DNA链
bool operator <(const Gene &a) const;
GeneNode*recombination(GeneNode*dna);//基因重组
void mutation(GeneNode*dna); //基因突变
GeneNode*propagate(); //繁殖后代。先复制一条链,并产生变异
void setDNA(GeneNode*i); //设置基因头节点
void kill(); //杀死该个体并释放DNA链表的空间
void printDNA(GeneNode*i); //将链状DNA递归输出
void printGene(); //将基因输出
};
Gene q[MAX_CAPCITY*2]; //生存空间,物竞天择,适者生存
GeneNode*init(); //初始化一个基因夏娃
void schedule(); //进行调度,算法的主体
涉及DNA链表的操作为数据结构基础,这里不再详解,只对主要的函数schedule进行讲解。
void schedule(){
int num = 1;
q[0].setDNA(init()); //初始化一个基因夏娃
while(num int tmp = num; for(int i=0;i q[tmp+i].setDNA(q[i].propagate());