蒙特卡洛加模拟退火算法的Matlab实现
本文最后更新于 2025年4月22日 下午
问题描述
- 一个企业生产一件产品共有M项任务需要完成,依次记为A、B、C、……
- 任务的完成需要遵循一定的顺序,A任务完成后才能去完成B,B完成后才能去完成C,以此类推,称为有顺序约束。
- 此时有N(N>=M)名员工可以完成这些任务,员工编号依次为1、2、3….,且每个员工只能固定完成一项任务
- 由于工作能力不同,每名员工完成不同任务耗费的时间不一样,如下表1所示。
任务/时间 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
A | 21 | 18 | 16 | 22 | 14 |
B | 35 | 28 | 33 | 26 | 22 |
C | 12 | 16 | 11 | 14 | 11 |
现按任务的顺序为各任务安排合适的员工,各员工按编号从小到大的顺序进行排队,对每一个员工可以做出同意或拒绝的选择,且只有一次机会,当选择同意时,按任务的先后顺序为此员工安排一项任务,当选择拒绝时,此员工离开队伍,后续不能再向其安排任务。例如:
当前最新任务为A,1号员工到来,拒绝1号完成任务A,1号离开,2号员工到来,接受2号员工完成任务A
当前最新任务变为B,3号员工到来,拒绝3号完成任务B,3号离开,4号员工到来,接受4号员工完成任务B
当前最新任务变为C,5号员工到来,接受5号员工完成任务C
因为条件5的限制,导致表1发生了一些变化,
- 1号员工不可能分配到任务B、C、…,因为这样就没有员工完成A了,同理有以下限制
- 2号员工不可能分配到任务C…
- 4号员工不可能分配到任务A…
- 5号员工不可能分配到任务A、B…
对于不可能分配到的任务,此员工完成时间记为无穷大,如下表2所示
任务/时间 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
A | 21 | 18 | 16 | ∞ | ∞ |
B | ∞ | 28 | 33 | 26 | ∞ |
C | ∞ | ∞ | 11 | 14 | 11 |
问此时如何为每一个任务分配一个员工去,能够达到生产一件产品耗费总时间最小?
分析问题
理想情况下,应该为每一个任务安排耗时最短的员工完成,可以看到,3号员工完成任务A,4号员工完成任务B,5号员工完成任务C,刚好满足条件,而且完美错开,可以达到总耗时最短的要求,总耗时为16+26+11=53。但是如果错不开怎么办,即某一个员工在完成多件任务都是耗时最短的情况下,就不能这么简单处理了,所以要考虑一般的情况。
一般的,在这个问题中,任务的完成是固定顺序,员工的选择也是从前到后,那么组合的情况就是123、124、134、235等等。可以认为是从5个员工中选3个,然后按顺序排队,依次分配一个任务,可以选择的组合数为$C^3_5$对每一种组合下计算对应的耗费时间,即可得到耗时最短的一种组合情况。
Matlab程序如下:
1 |
|
求出结果如下:

求出结果为3号员工完成任务A,4号员工完成任务B,5号员工完成任务C,此时耗费时间最短,最短时间为53
但是这是数据量比较少的情况,一旦数据增大,就不能再使用遍历了,比如,任务数为27,员工数为35,组合方式就达两千三百万种之多,此时需要寻找一种更好的方法

解决方法
更一般的,对于一个离散的组合优化问题,可以使用蒙特卡洛加模拟退火算法解决
算法步骤描述如下:
step1:使用蒙特卡洛方法生成随机选择一个最优的组合,作为初始解,并计算初始能量值(目标函数值)
step2:初始化模拟退火算法参数,初始温度T,终止温度e,温度衰减因子alf,马尔科夫链长度L,能量不再降低的次数上限cnt_limit
step3:马尔科夫链长度加1,判断是否达到上限,若是,算法结束,否则,开始step4
step4:当前温度下,在当前解的基础上进行扰动构造一个新解,本文中构造方法为:先将当前解的组合中随机去掉一个员工,再随机添加一个新员工。生成一个新解(一种组合),并计算能量值,即目标函数值(耗费总时间)
step5:计算与前一个解的能量之差
step6:根据能量差判断是否接受新解。若能量差小于0 ,说明新解的能量更低,接受新解;否则 ,说明新解的能量没有下降,以玻尔兹曼概率接受新解。同时记录最优解和对应的最低能量值(最小目标函数值)
step7:判断最低能量值是否保持不变,若是,计数器加1,否则,计数器清0。若计数器到达上限,算法结束。
step8:降低温度,判断温度是否达到下限,若是,算法结束,否则,转向step3
程序如下:
1 |
|
运行结果
记录两次较好的运行结果
运行结果1:

运行结果2:

更改任务数、员工总数,程序也能很快的完成收敛。当然模拟退火每次运行结果不一样,可以多运行几次,记录一个较好的结果,这样能够在短时间内得到一个较好解方案。通过遍历法可以验证模拟退火算法结果的有效性,其结果保持一致,但模拟退火算法可以更快得出结果。

结论
本文首先对有顺序约束的任务指派问题进行了分析,有顺序约束即任务的完成有先后顺序之分,员工的选取也有先后顺序之分,即只能向后选取,在这个限制条件下,本文先给出了遍历法的解决方法,并给出了Matlab代码和示例结果;然后再提出在任务数和员工数增大的情况下遍历法不再适用,因为本质上这是一个离散的组合优化问题,由此引入了蒙特卡洛算法加模拟退火算法的解决思路,并给出了算法步骤和Matlab代码以及示例结果。
本文的模拟退火算法与一般退火算法不同,由于本文的组合情况有顺序约束,常规退火算法中的扰动方法不再适用,本文使用方法为:在当前解中随机删除一个元素,再随机加入一个新元素的方法构造新解,最终取得了比较好的效果。
感谢博主“乐观的阿锡”乐观的阿锡的博客_CSDN博客-计算机,go语言,Linux系统编程学习笔记领域博主为本文提供了问题基础以及解决的思路
参考
[1] 李冰,徐杰,杜文.用模拟退火算法求解有顺序约束指派问题[J].系统工程理论方法应用,2002(04):330-335.
[2] 赵越.模拟退火算法求解指派问题新探[J].吉林建筑工程学院学报,2011,28(04):61-63.