任务调度算法
前言
本文介绍了任务调度算的应用场景,算法分析,遗传算法,国产2个优秀算法框架及实现旅行商问题的缺陷,最后根据遗传算法原理编码实现来规避缺陷
1 应用场景
任务调度时,有多达几十种调度任务,有的任务不依赖上一条任务,有的任务只有在上一条任务执行完后才能执行,每条任务执行期间设备都可能会移动一段距离,并且设备只会在一个固定的区域移动。任务调度时,如何使设备移动具体最小?
问题延伸一下,这里的任务调度目标是设备移动距离最小,调度目标也有可能是总任务完成时间最短。根据以往经验,从上一条任务执行到本任务都有一个时间,有开始时刻,结束时刻,可以构建一个n×n二维任务时刻矩阵,求任务完成时间最小值,等等。
上述问题非常典型,比如车间任务调度,巡检任务调度等等!
2 算法分析
根据需求,设备总移动距离是目标函数,有的任务只有在上一条任务执行完后才能执行,为顺序约束。这是一个排列组合问题,如果有n条任务,不考虑顺序约束,有n!种组合,15!是1,307,674,368,000种组合,30!是265,252,859,812,191,058,636,308,480,000,000种组合。这么庞大的组合数量,不可能用传统求和之后再比较得出最短距离。
针对上述分析结论,既然不能用传统算法,那么就需要用到大数据智能优化搜索算法,这些算法有差分进化算法,遗传算法,粒子群算法,模拟退火算法,蚁群算法,鱼群算法等等。排列组合,路径规划,是一个典型的旅行商问题,旅行商问题来源于遗传算法,问题归结于遗传算法的旅行商问题
3 遗传算法
遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。遗传算法已被人们广泛地应用于组合优化、机器学习、信号处理、自适应控制和人工生命等领域
3.1 简介
遗传算法的起源可追溯到20世纪60年代初期。1967年,美国密歇根大学J. Holland教授的学生 Bagley在他的博士论文中首次提出了遗传算法这一术语,并讨论了遗传算法在博弈中的应用,但早期研究缺乏带有指导性的理论和计算工具的开拓。1975年, J. Holland等提出了对遗传算法理论研究极为重要的模式理论,出版了专著《自然系统和人工系统的适配》,在书中系统阐述了遗传算法的基本理论和方法,推动了遗传算法的发展。20世纪80年代后,遗传算法进入兴盛发展时期,被广泛应用于自动控制、生产计划、图像处理、机器人等研究领域。
3.2 基本框架
3.2.1 编码
3.2.2 适应度函数
3.2.3 初始群体选取
3.3 运算过程
3.3.1 选择
3.3.2 交叉
3.2.3 变异
3.2.4 终止条件
3.3 特点
3.4 不足之处
3.5 应用
3.5.1 函数优化
3.5.2 组合优化
3.5.3 车间调度
4 智能搜索算法框架
智能搜索算法主流国产开源框架有geatpy和scikit-opt
4.1 geatpy
4.1.1 开源地址
https://github.com/geatpy-dev/geatpy
4.1.2 简介
geatpy团队现由华南农业大学、暨南大学、华南理工大学等优秀硕士以及一批优秀校友、优秀本科生组成。geatpy是一个高性能实用型进化算法工具箱,提供了许多已实现的进化算法各项操作的函数,如初始化种群、选择、交叉、变异、多目标优化参考点生成、非支配排序、多目标优化GD、IGD、HV等指标的计算等等。没有繁杂的深度封装,可以清晰地看到其基本结构及相关算法的实现,并利用geatpy函数方便地进行自由组合,实现和研究多种改进的进化算法、多目标优化、并行进化算法等,解决传统优化算法难以解决的问题。
geatpy在Python上提供简便易用的面向对象的进化算法框架。通过继承问题类,可以轻松把实际问题与进化算法相结合。geatpy还提供多种进化算法模板类,涵盖遗传算法、差分进化算法、进化策略、多目标进化优化算法等,可以通过调用算法模板,轻松解决单目标优化、多目标优化、组合优化、约束优化等问题。这些都是开源的,你可以参照这些模板,加以改进或重构,以便实现效果更好的进化算法,或是让进化算法更好地与当前正在进行的项目进行融合。
4.1.3 旅行商问题求解
import numpy as np import geatpy as ea class MyProblem(ea.Problem): # 继承Problem父类 def __init__(self): name = 'MyProblem' # 初始化name(函数名称,可以随意设置) M = 1 # 初始化M(目标维数) maxormins = [1] # 初始化maxormins(目标最小最大化标记列表,1:最小化该目标;-1:最大化该目标) Dim = 9 # 初始化Dim(决策变量维数) varTypes = [1] * Dim # 初始化varTypes(决策变量的类型,元素为0表示对应的变量是连续的;1表示是离散的) lb = [1] * Dim # 决策变量下界 ub = [9] * Dim # 决策变量上界 lbin = [1] * Dim # 决策变量下边界(0表示不包含该变量的下边界,1表示包含) ubin = [1] * Dim # 决策变量上边界(0表示不包含该变量的上边界,1表示包含) # 调用父类构造方法完成实例化 ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin) # 新增一个属性存储旅行地坐标 self.places = np.array([[0.4, 0.4439], [0.2439, 0.1463], [0.1707, 0.2293], [0.2293, 0.761], [0.5171, 0.9414], [0.8732, 0.6536], [0.6878, 0.5219], [0.8488, 0.3609], [0.6683, 0.2536], [0.6195, 0.2634]]) def aimFunc(self, pop): # 目标函数 x = pop.Phen # 得到决策变量矩阵 X = np.hstack([np.zeros((x.shape[0], 1)), x, np.zeros((x.shape[0], 1))]).astype(int) # 添加从0地出发且最后回到出发地 ObjV = [] # 存储所有种群个体对应的总路程 for i in range(X.shape[0]): journey = self.places[X[i], :] # 按既定顺序到达的地点坐标 distance = np.sum(np.sqrt(np.sum(np.diff(journey.T) ** 2, 0))) # 计算总路程 ObjV.append(distance) pop.ObjV = np.array([ObjV]).T # 把求得的目标函数值赋值给种群pop的ObjV # 找到违反约束条件的个体在种群中的索引,保存在向量exIdx中(如:若0、2、4号个体违反约束条件,则编程找出他们来) exIdx1 = np.where(np.where(x == 3)[1] - np.where(x == 6)[1] < 0)[0] exIdx2 = np.where(np.where(x == 4)[1] - np.where(x == 5)[1] < 0)[0] exIdx = np.unique(np.hstack([exIdx1, exIdx2])) pop.CV = np.zeros((pop.sizes, 1)) pop.CV[exIdx] = 1 # 把求得的违反约束程度矩阵赋值给种群pop的CV import matplotlib.pyplot as plt if __name__ == '__main__': """================================实例化问题对象============================""" problem = MyProblem() # 生成问题对象 """==================================种群设置==============================""" Encoding = 'P' # 编码方式,采用排列编码 NIND = 50 # 种群规模 Field = ea.crtfld(Encoding, problem.varTypes, problem.ranges, problem.borders) # 创建区域描述器 population = ea.Population(Encoding, Field, NIND) # 实例化种群对象(此时种群还没被初始化,仅仅是完成种群对象的实例化) """================================算法参数设置=============================""" myAlgorithm = ea.soea_SEGA_templet(problem, population) # 实例化一个算法模板对象 myAlgorithm.MAXGEN = 200 # 最大进化代数 myAlgorithm.mutOper.Pm = 0.5 # 变异概率 myAlgorithm.logTras = 1 # 设置每隔多少代记录日志,若设置成0则表示不记录日志 myAlgorithm.verbose = True # 设置是否打印输出日志信息 myAlgorithm.drawing = 1 # 设置绘图方式(0:不绘图;1:绘制结果图;2:绘制目标空间过程动画;3:绘制决策空间过程动画) """===========================调用算法模板进行种群进化========================""" [BestIndi, population] = myAlgorithm.run() # 执行算法模板,得到最优个体以及最后一代种群 BestIndi.save() # 把最优个体的信息保存到文件中 """==================================输出结果==============================""" print('评价次数:%s' % myAlgorithm.evalsNum) print('时间已过 %s 秒' % myAlgorithm.passTime) if BestIndi.sizes != 0: print('最短路程为:%s' % BestIndi.ObjV[0][0]) print('最佳路线为:') best_journey = np.hstack([0, BestIndi.Phen[0, :], 0]) for i in range(len(best_journey)): print(int(best_journey[i]), end=' ') # 绘图 plt.figure() plt.plot(problem.places[best_journey.astype(int), 0], problem.places[best_journey.astype(int), 1], c='black') plt.plot(problem.places[best_journey.astype(int), 0], problem.places[best_journey.astype(int), 1], 'o',c='black') for i in range(len(best_journey)): plt.text(problem.places[int(best_journey[i]), 0], problem.places[int(best_journey[i]), 1], chr(int(best_journey[i]) + 65), fontsize=20) plt.grid(True) plt.title('连线图') plt.xlabel('经度') plt.ylabel('经度') plt.savefig('roadmap.svg', dpi=600, bbox_inches='tight') else: print('没找到可行解。')
4.2 scikit-opt
4.2.1 开源地址
https://github.com/guofei9987/scikit-opt/
4.2.2 简介
是一款个人维护,容易上手,github上引用多,文档齐全,接近Python原生语法的智能优化群分算法
4.2.3 旅行商问题求解
import numpy as np from scipy import spatial import matplotlib.pyplot as plt font = {'family':'SimHei','weight':'bold','size':'9'} plt.rc('font',**font) plt.rc('axes',unicode_minus = False) #解决负号显示问题 num_points = 10 def task_distance(num_points,minValue, maxValue): li = np.array([[7,21,11,28,3,23,28,3,19,23], [11,3,2,17,12,30,21,18,25,5], [6,28,24,11,27,27,7,13,25,10], [26,21,12,11,16,17,18,14,25,19], [7,9,8,18,25,17,23,26,21,27], [30,11,26,2,13,8,3,20,5,25], [8,24,10,10,5,26,5,27,3,16], [28,23,28,11,22,2,15,11,13,16], [17,10,30,3,7,22,23,30,4,2], [16,29,10,28,8,10,2,8,10,2]]) return li def cal_total_distance(routine): num_points, = routine.shape sum =0; for i in range(num_points-1): sum += distance_matrix[routine[i],routine[i+1]] return sum from sko.GA import GA_TSP points_coordinate = task_distance(num_points,2,30) # generate coordinate of points distance_matrix = points_coordinate ga_tsp = GA_TSP(func=cal_total_distance, n_dim=num_points, size_pop=50, max_iter=20, prob_mut=1) best_points, best_distance = ga_tsp.run() print("best_points is ",best_points) print("best_distance is ", best_distance) #画图 best_points_ = best_points best_points_coordinate = points_coordinate[best_points_, :] plt.figure(1) plt.subplot(221,title='连线图') plt.xlabel("经度") plt.ylabel("纬度") plt.plot(best_points_coordinate[:, 0], best_points_coordinate[:, 1], 'o-r') plt.subplot(222,title='收敛图') plt.xlabel("迭代次数") plt.ylabel("最短距离") plt.plot(ga_tsp.generation_best_Y) plt.show()
4.3 旅行商问题开源框架缺陷
分析2种算法框架,有运行速度快,准确度高等特点,单旅行商无约束模型这2个框架都非常适合。
缺点也很明显,实际应用中,有顺序约束,也有几个车间任务,几个巡检任务同时调度,即多旅行商有约束的情况,这些框架算法就很难实现,甚至不支持,需要自行编码实现多旅行商有约束的遗传算法
5 自行编码实现任务调度
根据遗传算法原理,自行编码实现遗传算法,实现任务调度
5.1 旅行商类
import pandas as pd
import numpy as np import matplotlib.pyplot as plt font = {'family':'SimHei','weight':'bold','size':'9'} plt.rc('font',**font) plt.rc('axes',unicode_minus = False) #解决负号显示问题 class TPS(object): pop_size = 50 #种群大小 c_rate = 0.7 #交叉率 m_rate = 0.05 #突变率 pop = np.array([])#种群数量 fitness = np.array([]) #适应度数组 ga_num = 200 #最大迭代次数 best_distance = 1 #记录目前最优距离 best_gene = [] #记录目前最优任务调度方案 tasks = np.array([]) task_size = 0 #标记任务数目 tasks_distance = np.array([[[]]]) task_distance_start = 1 #任务开始位置 task_cons_order = np.array([[]])#顺序约束 task_cons_no = np.array([])
def __init__(self,c_rate,m_rate,pop_size,ga_num,start_pos,task_list,task_cons_order,tasks_cons_number): self.fitness = np.zeros(self.pop_size) self.c_rate = c_rate self.m_rate = m_rate self.pop_size = pop_size self.ga_num = ga_num self.task_distance_start = start_pos self.tasks_distance = np.array(task_list) self.task_size = self.tasks_distance.shape[1] self.tasks = np.arange(self.task_size) self.task_cons_order = np.array(task_cons_order) self.task_cons_no = np.array(tasks_cons_number) def init(self): self.pop = self.creat_pop(self.pop_size) self.fitness = self.get_fitness(self.pop) #计算种群适应度 def creat_pop(self,size): pop = [] for i in range(size): gene = self.creat_gene() #创建基因 pop.append(gene) #加入种群 return np.array(pop) def creat_gene(self,cons_order = True): gene = np.arange(self.task_size) # 问题的解,基因组合,种群中的个体 np.random.shuffle(gene) #打乱基因组合 if cons_order: gene = self.constraint_order(gene) #顺序约束 return gene def constraint_order(self,gene):#顺序约束 if len(self.task_cons_order)==0 or len(self.task_cons_order[0])==0:#无约束直接返回 return gene for i,elem_one in enumerate(gene):#选择排序 if gene[i] not in self.task_cons_no: continue for j,elem_two in enumerate(gene): if i==j: continue chage = self.change_order(gene[i],gene[j])#判断是否要调整顺序 if chage: gene[i],gene[j] = gene[j],gene[i] return gene def change_order(self,begin,end):#交换顺序 result,cycle = get_link_next(self.task_cons_order,begin,end) return result def get_fitness(self,pop): d = np.array([]) #适应度记录数组 for i in range(pop.shape[0]): gene = pop[i] #取个体 distance = self.get_distance(gene)#计算个体基因的优劣 distance = self.best_distance/distance #当前最优距离除以个体距离,越近适应度越高,最优适应度为1 d= np.append(d,distance) #保存种群中每个个体适应度 return d def get_distance(self,gene): s = 0 for i in range(len(gene)): if i==0: start_task = self.tasks_distance[0][gene[i]] start_distance_one = self.task_distance_start - start_task[0] start_distance_two = start_task[0]-start_task[1] s+= np.abs(start_distance_one) + np.abs(start_distance_two) else: s+= self.caculate_distance(gene[i-1],gene[i]) return s def caculate_distance(self,i,j): distance_one = self.tasks_distance[0][i][1]-self.tasks_distance[0][j][0] distance_two = self.tasks_distance[0][j][0]-self.tasks_distance[0][j][1] distance = np.abs(distance_one) + np.abs(distance_two) return distance def select_pop(self,pop): #低于平均的要替换改变 best_f_index = np.argmax(self.fitness) av = np.median(self.fitness, axis = 0) for i in range(self.pop_size): if i!=best_f_index and self.fitness[i] < av: pi = self.cross(pop[best_f_index],pop[i]) pi = self.mutate(pi) pop[i,:] = pi[:] return pop;
def cross(self,parent1,parent2):#交叉 if np.random.rand()>self.c_rate: return parent1 index1 = np.random.randint(0,self.task_size-1) index2 = np.random.randint(index1,self.task_size-1) tempGene = parent2[index1:index2] #交叉基因片段 newGene = [] pllen =0 for g in parent1: if pllen == index1: newGene.extend(tempGene) #插入基因片段 if g not in tempGene: newGene.append(g) pllen+=1 newGene = np.array(newGene) if newGene.shape[0]!=self.task_size: print('c error') return self.creat_pop(1) #newGene = self.constraint_order(newGene) #顺序约束 return newGene def mutate(self,gene):#变异 if np.random.rand()> self.m_rate: gene = self.constraint_order(gene) #顺序约束 return gene index1 = np.random.randint(0,self.task_size-1) index2 = np.random.randint(index1,self.task_size-1) newGene = self.reverse_gene(gene,index1,index2) if newGene.shape[0]!=self.task_size: print('m error') return self.creat_pop(1) newGene = self.constraint_order(newGene) #顺序约束 return newGene def reverse_gene(self,gene,i,j):#反转 #翻转基因中i到j之间的基因片段 if i>=j: return gene if j>self.task_size-1: return gene parent1 = np.copy(gene) tempGene = parent1[i:j] newGene = [] pllen = 0 for g in parent1: if pllen==i: newGene.extend(tempGene[::-1]) #插入基因片段 if g not in tempGene: newGene.append(g) pllen+=1 return np.array(newGene) def evelution(self): #主程序:迭代进化种群 best_iteration = 0; best_gene = [] best_distance =0 tsp = self x_axis = [] y_axis = [] for i in range(self.ga_num): best_f_index = np.argmax(tsp.fitness) worst_f_index = np.argmin(tsp.fitness) local_best_gene = tsp.pop[best_f_index] local_best_distance = tsp.get_distance(local_best_gene) if i ==0: tsp.best_gene = local_best_gene tsp.best_distance = tsp.get_distance(local_best_gene) best_gene = tsp.best_gene best_distance = tsp.best_distance if local_best_distance < best_distance: best_iteration = i tsp.best_distance = local_best_distance #记录最优值 tsp.best_gene = local_best_gene #记录最优个体基因 best_gene = tsp.best_gene best_distance = tsp.best_distance else: tsp.pop[worst_f_index] = tsp.cross(self.creat_gene(cons_order = False),best_gene) tsp.pop[worst_f_index] = tsp.mutate(tsp.pop[worst_f_index]) this_best_distance = self.get_distance(self.best_gene) x_axis.append(i+1) y_axis.append(this_best_distance) print('当前迭代:%d 全局最优值:%s 本次最优值:%s 本次最优染色体:%s'%(i+1,best_distance,this_best_distance,self.best_gene)) tsp.pop = tsp.select_pop(tsp.pop) #选择淘汰种群 #创建新种群 best_gene_number = 0 #保留一条最优解 for j in range(self.pop_size): best_gene_equal = (tsp.pop[j] == best_gene).all() if best_gene_equal: best_gene_number+=1 #print("第%d次迭代包含相等的最优距离,个数%d"%(i+1,best_gene_number)) if best_gene_equal==False or best_gene_number>1: r = np.random.randint(0,self.pop_size-1) if j!=r: tsp.pop[j] == tsp.cross(tsp.pop[j],tsp.pop[r]) #交叉种群中第j,r个体的基因 tsp.pop[j] = tsp.mutate(tsp.pop[j]) #突变种群中第j个个体基因 self.fitness = self.get_fitness(self.pop) #计算种群适应度
plt.xlabel("迭代次数") plt.ylabel("最短距离") plt.title("收敛图(第%d次迭代出现最短距离%d)"%(best_iteration+1,best_distance)) plt.plot(x_axis,y_axis) plt.show() print('最优迭代:%d 最优值:%s 最优染色体:%s'%(best_iteration+1,best_distance,best_gene)) best_gene_str = self.get_gene_str(best_gene) result = "%d|%s"%(best_distance,best_gene_str) print(result) return result def get_gene_str(self,gene): genStr = '' for i in gene: genStr += str(i)+"," return genStr[0:-1]
5.2 辅助函数
def get_task_into(t): #转为任务列表 #t=1,1|2,2|3,3|4,4|5,5|6,6|7,7|8,8|9,9|10,10 task = [] #任务 task_list = [] #任务列表 cons_order_list = [] #顺序约束列表 task_cons_no = [] for i,elem_one in enumerate(t.split("|")): task_bay = []#贝位:开始贝位,结束贝位 cons_order =[] #顺序约束 for j,elem_two in enumerate(elem_one.split(",")): if j<2: task_bay.append(int(elem_two)) elif j==2 and elem_two!='': cons_order.append(i) end = int(elem_two) cons_order.append(end) cons_order_list.append(cons_order) if i not in task_cons_no: task_cons_no.append(i) if end not in task_cons_no: task_cons_no.append(end) task.append(task_bay) task_list.append(task) return task_list,cons_order_list,task_cons_no def dead_cycle(arr):#死循环判断 arr = np.array([[5,1],[1,3],[3,5]]) for i in range(len(arr)): if len(arr[i])==0: continue begin,end = arr[i][0],arr[i][1] result,cycle = get_link_next(arr,begin,end) if result: print("发生死循环任务编号%d"%(cycle)) return result return False def get_link_next(arr,begin,end):#获取链路下一个,返回是否死循环和最后的 for j in range(len(arr)): if len(arr[j])==0 or (begin == arr[j][0] and end == arr[j][1]): #排除本身 continue if end == arr[j][0]: #向后 if begin == arr[j][1]: #print("发生死循环任务指针编号%d,%d"%(begin,end)) return True,end else: end = arr[j][1] result = get_link_next(arr,begin,end) return result return False,end
5.3 调用主方法
if __name__ == '__main__': #app.run(debug=True, port=8888,host=0.0.0.0) #指定端口、host,0.0.0.0代表不管几个网卡,任何ip都可以访问 start_pos = int(1) task_list,cons_order,task_cons_no = get_task_into('1,1|2,2,3,|3,3|4,4|5,5|6,6|7,7|8,8|9,9|10,10|1,1|2,2|3,3|4,4|5,5') dead = dead_cycle(np.array(cons_order)) #验证死循环 if dead: print("发生死循环了") else: iteration = len(task_cons_no) print("顺序约束任务个数数为%d"%(iteration)) iteration = 16-len(task_cons_no) if iteration <=0: iteration =1 self = TPS(0.8,0.05,2000,iteration,start_pos,task_list,cons_order,task_cons_no) self.init() result = self.evelution()
5.4 WISG run_server部署方法
#导入WISG(Web Server Gateway Interface) from wsgiref.simple_server import make_server from urllib import parse import json import pdb
def getSingleTaskSchedule(environ,start_response):
start_response('200 OK',[('Content-Type','text/html;charset=urf-8')]) #调用urlparse的parse_qs解析URL参数,并返回字典 query_args=environ['QUERY_STRING'] params = parse.parse_qs(query_args) start_pos_value = params['startPos'] task_list_value = params['taskList'] # 获取get中key为name的值 start_pos = int(str(start_pos_value).replace("[","").replace("]","").replace("'","")) task_list,cons_order,tasks_cons_number = get_task_into(str(task_list_value).replace("[","").replace("]","").replace("'","")) dead = dead_cycle(np.array(cons_order)) #验证死循环 if dead: result = json.dumps("-9998|任务死循环").encode('utf-8') return [result] else: iteration = len(tasks_cons_number) print("顺序约束任务个数数为%d"%(iteration)) iteration = 16-len(tasks_cons_number) if iteration <=0: iteration =1 self = TPS(0.7,0.05,2000,iteration,start_pos,task_list,cons_order,tasks_cons_number) self.init() result = json.dumps(self.evelution()).encode('utf-8') return [result] return [result] def get_url(): data= {'/getSingleTaskSchedule':getSingleCraneSchedule}
return data def run_server(environ,start_response): urls=get_url() url=environ.get("PATH_INFO") print(url) if url in urls: function_data = urls[url](environ,start_response) return function_data else: start_response("200 OK",[('Content-Type','text/html;charset=utf-8')]) result = [bytes("-9999|路由错误",encoding="utf-8")] return result httpd =make_server('0.0.0.0',8801,run_server) # ip='0.0.0.0' port=8801 print("server is started, port is 8801....") httpd.serve_forever()
5.5 运行结果
顺序约束任务个数数为2 当前迭代:1 全局最优值:28 本次最优值:28 本次最优染色体:[14 4 9 8 7 6 2 3 12 13 5 11 10 1 0] 当前迭代:2 全局最优值:24 本次最优值:24 本次最优染色体:[14 4 9 8 7 6 5 2 3 12 13 11 10 1 0] 当前迭代:3 全局最优值:20 本次最优值:20 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 10 1 0] 当前迭代:4 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:5 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:6 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:7 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:8 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:9 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:10 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:11 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:12 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:13 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0] 当前迭代:14 全局最优值:18 本次最优值:18 本次最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0]
最优迭代:4 最优值:18 最优染色体:[14 4 9 8 7 6 5 3 13 2 12 11 1 10 0]
18|14,4,9,8,7,6,5,3,13,2,12,11,1,10,0
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下