当前位置: 首页 > news >正文

数学建模学习(111):改进遗传算法(引入模拟退火、轮盘赌和网格搜索)求解JSP问题

文章目录

  • 一、车间调度问题
    • 1.1目前处理方法
    • 1.2简单案例
  • 二、基于改进遗传算法求解车间调度
    • 2.1车间调度背景介绍
    • 2.2遗传算法介绍
      • 2.2.1基本流程
      • 2.2.2遗传算法的基本操作和公式
      • 2.2.3遗传算法的优势
      • 2.2.4遗传算法的不足
    • 2.3讲解本文思路及代码
    • 2.4算法执行结果:
  • 三、本文代码创新点
  • 四、附上完整代码

一、车间调度问题

  车间作业调度问题(JSP)是生产调度领域的经典问题之一,广泛应用于制造业、物流等领域。在一个典型的车间中,多个工件需要在多台机器上按特定的顺序进行加工。每个工件的加工步骤及其顺序是预先确定的,不同工件的加工顺序可能不同。 车间作业调度问题的目标是确定工件在各机器上的加工顺序,以最小化所有工件的完成总时间(即 makespan)。

1.1目前处理方法

  车间作业调度问题因其高度的复杂性和计算上的挑战性,被归类为NP难问题。为了解决这一问题,学术界和工业界已经提出了多种方法,涵盖了精确算法、启发式算法以及元启发式算法。
  精确算法,如分支定界法和动态规划,理论上能够找到全局最优解,但由于其高计算复杂度,通常不适用于大规模问题。
  启发式算法,例如优先规则,如最短加工时间优先(SPT)和最早截止时间优先(EDD),通过简单的规则快速生成可行解。尽管这些方法计算速度快,但解的质量往往无法得到保证。
  元启发式算法,包括遗传算法(GA)、模拟退火(SA)和粒子群优化(PSO),在处理复杂优化问题时表现出色。遗传算法通过模拟自然选择和遗传机制来不断优化解的种群;模拟退火算法通过模拟物质冷却过程中的能量变化来避免局部最优;粒子群优化算法则通过模拟鸟群觅食行为在多维空间中搜索全局最优解。
  近年来,混合算法也逐渐受到关注,例如结合遗传算法和禁忌算法的混合算法,能够利用不同算法的优势,提高解的质量和求解效率。

1.2简单案例

  我们假设有三个机器(M1, M2, M3)和三个工件(J1, J2, J3),每个工件已有不同的加工步骤和时间。这是一个简单的示例:
  假设加工步骤和时间如下:
  J1: M1(3) → M2(2) → M3(2)
  J2: M2(4) → M3(1) → M1(3)
  J3: M3(2) → M1(4) → M2(3)
  以时间为x轴,每个机器为y轴,利用Python求解,每种工件代表1种颜色,可绘制甘特图如下所示:
请添加图片描述
  绘图相应代码如下:

import matplotlib.pyplot as plt
import random
plt.rcParams['font.sans-serif'] = ['SimHei']
# 创建一个表示任务的列表,每个任务用一个字典表示
tasks = [{"Task": "J1", "Machine": "M1", "Start": 0, "Finish": 3},{"Task": "J1", "Machine": "M2", "Start": 3, "Finish": 5},{"Task": "J1", "Machine": "M3", "Start": 5, "Finish": 7},{"Task": "J2", "Machine": "M2", "Start": 0, "Finish": 4},{"Task": "J2", "Machine": "M3", "Start": 4, "Finish": 5},{"Task": "J2", "Machine": "M1", "Start": 5, "Finish": 8},{"Task": "J3", "Machine": "M3", "Start": 0, "Finish": 2},{"Task": "J3", "Machine": "M1", "Start": 2, "Finish": 6},{"Task": "J3", "Machine": "M2", "Start": 6, "Finish": 9},
]
# 创建一个新的图形
fig, gnt = plt.subplots()# 设置Y轴
gnt.set_ylim(0, 40)
gnt.set_xlim(0, 12)
# 设置Y轴标签
gnt.set_yticks([10, 20, 30])
gnt.set_yticklabels(['M1', 'M2', 'M3'])
# 设置X轴标签
gnt.set_xlabel('时间')
gnt.set_ylabel('机器')
# 生成不同的颜色,每个工件一个颜色
task_colors = {}
for task in tasks:if task["Task"] not in task_colors:task_colors[task["Task"]] = (random.random(), random.random(), random.random())
# 绘制任务
for task in tasks:machine_map = {"M1": 10, "M2": 20, "M3": 30}start = task["Start"]finish = task["Finish"]machine = machine_map[task["Machine"]]color = task_colors[task["Task"]]gnt.broken_barh([(start, finish - start)], (machine - 5, 9), facecolors=color)
# 显示甘特图
plt.show()

二、基于改进遗传算法求解车间调度

2.1车间调度背景介绍

  在一个车间内,有10台机器,每台机器负责一道加工步骤。这些机器需要完成10个工件的加工,每个工件都有10个加工步骤。不同工件的加工步骤顺序各不相同且顺序不可更改。每个加工步骤由对应的机器在一定时间内完成。你需要确定各个工件在不同机器上的加工顺序,以最小化所有工件完成加工所需的总时间。具体的不同工件加工顺序与加工时长如下表所示:
在这里插入图片描述
  对于每个工件,其加工顺序和每台机器上的加工耗时一定,拿第一行举例。工件1的加工顺序为:M1-M2-M4-M3-M5-M6-M8-M4-M7-M10。其花费时间固定,分别为28-33-11-48-18-19-86-64-65-90。我们要做的就是对机器进行调度,什么时候加工第几个工件的第几个工序

2.2遗传算法介绍

  遗传算法(Genetic Algorithm,GA)是一类模拟自然选择和遗传机制的进化算法,主要用于优化和搜索问题。它最早由约翰·霍兰德(John Holland)在20世纪70年代提出。遗传算法通过模拟自然界生物进化的过程,包括选择、交叉(杂交)和变异等操作,逐步优化问题的解。

2.2.1基本流程

  1. 初始化种群:随机生成一定数量的初始解,称为个体,这些个体构成初始种群。
  2. 适应度评估:计算每个个体的适应度值,适应度值越高表示该个体越适合问题的求解。
  3. 选择:根据个体的适应度值,选择一些个体作为父代。常用的选择方法有轮盘赌选择、锦标赛选择等。
  4. 交叉:通过交叉操作(即杂交)生成新的个体,交叉操作将两个父代个体的部分基因交换,从而生成子代个体。
  5. 变异:对新生成的个体进行变异操作,即随机改变个体的一部分基因,以增加种群的多样性。
  6. 生成新种群:用子代个体替换部分或全部父代个体,形成新一代种群。
  7. 重复迭代:重复上述步骤,直到满足终止条件,如达到最大迭代次数或种群中的最佳适应度值达到预期目标。

2.2.2遗传算法的基本操作和公式

  1. 选择操作:选择操作通过适应度值选择个体。轮盘赌选择法的概率计算公式:
    P i = f i ∑ j = 1 N f j P_i = \frac{f_i}{\sum_{j=1}^{N} f_j} Pi=j=1Nfjfi
    其中,(P_i) 是第 (i) 个个体被选中的概率,(f_i) 是第 (i) 个个体的适应度值,(N) 是种群的大小。
  2. 交叉操作:交叉操作将两个父代个体的基因部分交换,生成两个新的个体。单点交叉的公式:
    子代1 = ( 父代1 1 , 父代1 2 , … , 父代1 c , 父代2 c + 1 , … , 父代2 n ) 子代2 = ( 父代2 1 , 父代2 2 , … , 父代2 c , 父代1 c + 1 , … , 父代1 n ) \begin{aligned} &\text{子代1} = (\text{父代1}_1, \text{父代1}_2, \ldots, \text{父代1}_c, \text{父代2}_{c+1}, \ldots, \text{父代2}_n) \\ &\text{子代2} = (\text{父代2}_1, \text{父代2}_2, \ldots, \text{父代2}_c, \text{父代1}_{c+1}, \ldots, \text{父代1}_n) \end{aligned} 子代1=(父代11,父代12,,父代1c,父代2c+1,,父代2n)子代2=(父代21,父代22,,父代2c,父代1c+1,,父代1n)
    其中,(c) 是交叉点的位置,(\text{父代1}) 和 (\text{父代2}) 是两个父代个体,(n) 是个体的基因长度。
  3. 变异操作:变异操作随机改变个体的一部分基因。对于一个基因序列 (x = (x_1, x_2, \ldots, x_n)),其变异公式可以表示为:
    x i ′ = { 随机值 如果 随机概率 < 变异概率 x i 否则 x_i' = \begin{cases} \text{随机值} & \text{如果 } \text{随机概率} < \text{变异概率} \\ x_i & \text{否则} \end{cases} xi={随机值xi如果 随机概率<变异概率否则
    其中,(x_i’) 是变异后的基因值,变异概率通常设为一个小值,如0.01或0.1。

2.2.3遗传算法的优势

  • 全局搜索能力强:遗传算法通过选择、交叉和变异等操作,可以在较大范围内进行搜索,能够较好地避免陷入局部最优。
  • 适用范围广:遗传算法适用于各种优化问题,包括离散问题和连续问题。
  • 易于并行化:由于种群中的个体可以并行计算适应度值,遗传算法易于实现并行计算,提升计算效率。

2.2.4遗传算法的不足

  • 计算开销大:遗传算法需要多次迭代,且每次迭代需要计算多个个体的适应度值,计算开销较大。
  • 参数选择复杂:遗传算法的性能对参数(如种群大小、交叉率、变异率等)依赖较大,参数选择不当可能影响算法效果。
  • 收敛速度慢:在某些情况下,遗传算法的收敛速度较慢,可能需要较多的迭代次数才能找到较优的解。

2.3讲解本文思路及代码

  本文改进遗传算法的代码更侧重于结合多种优化算法解决问题。利用网格搜索找到最优参数,并且在搜索过程中结合模拟退火算法进行局部优化,探索了更大范围的解空间,寻找最优解的可能性更大,利用上述显著优势尝试求解JSP问题。
  Step1:初始化。创建一个初始种群,每个个体代表一个可能的作业顺序。通过随机生成的方式确保种群的多样性。

def createPop(Jm, popSize):pop = []for i in range(popSize):pop.append(createInd(Jm))return pop

  Step2:选择。使用轮盘赌选择方法,根据个体的适应度(即完工时间)概率性地选择个体。适应度越高(即完工时间越短),被选择的概率越大。

def roulette_wheel_selection(fitness):total_fitness = sum(fitness)pick = random.uniform(0, total_fitness)current = 0for i, fit in enumerate(fitness):current += fitif current > pick:return i

  Step3:交叉。应用自定义的交叉操作,将父代个体组合生成新的后代。通过选择两个父代个体,交换它们的一部分基因片段,以继承父母双方的特征。

def cross(A, B):n = len(A)r1 = np.random.randint(n)r2 = np.random.randint(n)rl, rr = min(r1, r2), max(r1, r2)if rl == rr:return A, Bbt = copy.deepcopy(B)afinal = copy.deepcopy(A)for i in range(rl, rr + 1):bt.remove(A[i])k = 0for i in range(n):if i < rl or i > rr:afinal[i] = bt[k]k += 1at = copy.deepcopy(A)bfinal = copy.deepcopy(B)for i in range(rl, rr + 1):at.remove(B[i])k = 0for i in range(n):if i < rl or i > rr:bfinal[i] = at[k]k += 1return afinal, bfinal

  Step4:变异。通过随机交换作业操作引入变异,以保持基因多样性。变异操作有助于防止算法陷入局部最优。

def mutate(individual, mutation_rate):if random.random() < mutation_rate:index1, index2 = random.sample(range(len(individual)), 2)individual[index1], individual[index2] = individual[index2], individual[index1]return individual

  Step5:解码。使用详细的调度算法解码每个个体,以评估其完工时间,确保所有作业约束得到满足。解码过程包括为每个作业在特定机器上安排开始和结束时间。

def decode(J, P, s):n, m = J.shapeT = [[[0]] for _ in range(m)]C = np.zeros((n, m))k = np.zeros(n, dtype=int)for job in s:if job < 0 or job >= n:print(f"Invalid job index: {job}")continueif k[job] < 0 or k[job] >= m:print(f"Invalid operation index for job {job}: {k[job]}")continuemachine = J[job, k[job]] - 1process_time = P[job, k[job]]last_job_finish = C[job, k[job] - 1] if k[job] > 0 else 0start_time = max(last_job_finish, T[machine][-1][-1])insert_index = len(T[machine])for i in range(1, len(T[machine])):gap_start = max(last_job_finish, T[machine][i - 1][-1])gap_end = T[machine][i][0]if gap_end - gap_start >= process_time:start_time = gap_startinsert_index = ibreakend_time = start_time + process_timeC[job, k[job]] = end_timeT[machine].insert(insert_index, [start_time, job, k[job], end_time])k[job] += 1M = [[] for _ in range(m)]for machine in range(m):for j in T[machine][1:]:M[machine].append(j[1])return T, M, C

  Step6:模拟退火。为了增强搜索能力,本文结合模拟退火方法,对个体解进行微调,允许偶尔接受较差解,以跳出局部最优。模拟退火通过**逐渐降低“温度”**来减少接受较差解的概率,从而达到全局优化的效果。

def simulated_annealing(individual, J, P, T0, alpha, max_iter):current_solution = copy.deepcopy(individual)Tmax, _, current_fitness = decode(J, P, current_solution)best_solution = copy.deepcopy(current_solution)best_fitness = current_fitness.max()T = T0for i in range(max_iter):new_solution = mutate(copy.deepcopy(current_solution), 1.0)Tmax, _, new_fitness = decode(J, P, new_solution)delta_fitness = new_fitness.max() - current_fitness.max()if delta_fitness < 0 or random.random() < math.exp(-delta_fitness / T):current_solution = new_solutioncurrent_fitness = new_fitnessif current_fitness.max() < best_fitness:best_solution = copy.deepcopy(current_solution)best_fitness = current_fitness.max()T *= alphareturn best_solution, best_fitness

  Step7:算法执行过程。通过初始化种群并不断执行选择、交叉、变异和解码操作,结合模拟退火优化,遗传算法逐步优化种群中的个体。每一代后,种群会逐步接近最优解,最终输出最优的调度方案。以下是主函数部分,展示了算法的执行过程:

# 主函数
if __name__ == "__main__":J, P = load_data('05.txt')pop_size = 50max_iter = 5000w = 0.5c1 = 1.5c2 = 1.5best_position, best_fitness = pso(J, P, pop_size, max_iter, w, c1, c2)print(f'Best Solution: {best_position}')print(f'Best Fitness: {best_fitness}')T, M, C = decode(J, P, best_position)drawGantt(T)plt.show()

2.4算法执行结果:

  经过长时间运行,本文得到最少用时为 893s, 由网格搜索得到的具体参数如下所示:
在这里插入图片描述

三、本文代码创新点

  • 创新1:引入混合优化算法。本文结合了遗传算法、模拟退火和网格搜索三种优化方法,提升了搜索效率和解的质量。遗传算法利用选择、交叉和变异操作进行全局搜索,模拟退火通过局部搜索进一步优化解,而网格搜索则用于寻找最佳的参数组合。

  • 创新2:采用网格搜索。param_grid定义了一系列参数范围,通过遍历所有参数组合,自动化寻找最佳参数设置,确保算法在参数空间内找到最优解。

  • 创新3:引入模拟退火策略。在遗传算法的基础上,引入模拟退火策略,有效地跳出局部最优解,进一步提升解的质量。通过控制退火过程的温度,平衡了探索与开发。

  • 创新4:自适应交叉和变异操作。交叉和变异操作的实现更加灵活,能够根据个体特性进行调整。变异操作通过概率控制增加了种群的多样性,帮助避免过早收敛。

  • 创新5:甘特图绘制。通过rawGantt函数,使用不同颜色表示不同工件的操作,并在甘特图上显示详细的操作信息,提供了直观的调度结果可视化。

  • 创新6:基于轮盘赌选择。采用轮盘赌选择机制,增加了适应度高的个体被选中的概率,确保了优良基因的传递,提高了算法的收敛速度和效果。

四、附上完整代码

import copy
import numpy as np
import matplotlib.pyplot as plt
import random
import math
#------------------------------------------------------------------------------------------------------------------#-------------------------------------------------------------------------------------
def createInd(J):#创建个体n = J.shape[0]s = []Jm = J.copy()while not np.all(Jm == 0):I = np.random.randint(0, n)M = Jm[I, 0]if M != 0:s.append(I)b = np.roll(Jm[I, :], -1)b[-1] = 0Jm[I, :] = breturn sdef createPop(Jm, popSize):#创建种群pop = []for i in range(popSize):pop.append(createInd(Jm))return popdef decode(J, P, s):#解码n, m = J.shapeT = [[[0]] for _ in range(m)]C = np.zeros((n, m))k = np.zeros(n, dtype=int)for job in s:machine = J[job, k[job]] - 1process_time = P[job, k[job]]last_job_finish = C[job, k[job] - 1] if k[job] > 0 else 0start_time = max(last_job_finish, T[machine][-1][-1])insert_index = len(T[machine])for i in range(1, len(T[machine])):gap_start = max(last_job_finish, T[machine][i - 1][-1])gap_end = T[machine][i][0]if gap_end - gap_start >= process_time:start_time = gap_startinsert_index = ibreakend_time = start_time + process_timeC[job, k[job]] = end_timeT[machine].insert(insert_index, [start_time, job, k[job], end_time])k[job] += 1M = [[] for _ in range(m)]for machine in range(m):for j in T[machine][1:]:M[machine].append(j[1])return T, M, Cdef drawGantt(timelist):#绘制甘特图T = timelist.copy()plt.rcParams['font.sans-serif'] = ['SimHei']fig, ax = plt.subplots(figsize=(10, 6))color_map = {}for machine in T:for task_data in machine[1:]:job_idx, operation_idx = task_data[1], task_data[2]if job_idx not in color_map:color_map[job_idx] = (random.random(), random.random(), random.random())for machine_idx, machine_schedule in enumerate(T):for task_data in machine_schedule[1:]:start_time, job_idx, operation_idx, end_time = task_datacolor = color_map[job_idx]ax.barh(machine_idx, end_time - start_time, left=start_time, height=0.4, color=color)label = f'{job_idx}-{operation_idx}'ax.text((start_time + end_time) / 2, machine_idx, label, ha='center', va='center', color='white', fontsize=10)ax.set_yticks(range(len(T)))ax.set_yticklabels([f'machine{i + 1}' for i in range(len(T))])plt.xlabel("时间")plt.title("JSP甘特图")l = []for job_idx, color in color_map.items():l.append(plt.Rectangle((0, 0), 1, 1, color=color, label=f'{job_idx}'))plt.legend(handles=l, title='工件')def cross(A, B):#交叉操作n = len(A)r1 = np.random.randint(n)r2 = np.random.randint(n)rl, rr = min(r1, r2), max(r1, r2)if rl == rr:return A, Bbt = copy.deepcopy(B)afinal = copy.deepcopy(A)for i in range(rl, rr + 1):bt.remove(A[i])k = 0for i in range(n):if i < rl or i > rr:afinal[i] = bt[k]k += 1at = copy.deepcopy(A)bfinal = copy.deepcopy(B)for i in range(rl, rr + 1):at.remove(B[i])k = 0for i in range(n):if i < rl or i > rr:bfinal[i] = at[k]k += 1return afinal, bfinaldef load_data(path):#载入操作with open(path, 'r') as file:lines = file.readlines()job_num, machines_num = map(int, lines[0].split())J = np.zeros((job_num, len(lines[1].split()) // 2), dtype=int)P = np.zeros((job_num, len(lines[1].split()) // 2), dtype=int)for i in range(1, len(lines)):data = list(map(int, lines[i].split()))for j in range(len(data)):if j % 2 == 0:J[i - 1][j // 2] = data[j]else:P[i - 1][j // 2] = data[j]return J, Pdef mutate(individual, mutation_rate):#变异操作if random.random() < mutation_rate:index1, index2 = random.sample(range(len(individual)), 2)individual[index1], individual[index2] = individual[index2], individual[index1]return individualdef roulette_wheel_selection(fitness):#轮盘赌total_fitness = sum(fitness)pick = random.uniform(0, total_fitness)current = 0for i, fit in enumerate(fitness):current += fitif current > pick:return idef simulated_annealing(individual, J, P, T0, alpha, max_iter):#模拟退火current_solution = copy.deepcopy(individual)Tmax, _, current_fitness = decode(J, P, current_solution)best_solution = copy.deepcopy(current_solution)best_fitness = current_fitness.max()T = T0for i in range(max_iter):new_solution = mutate(copy.deepcopy(current_solution), 1.0)Tmax, _, new_fitness = decode(J, P, new_solution)delta_fitness = new_fitness.max() - current_fitness.max()if delta_fitness < 0 or random.random() < math.exp(-delta_fitness / T):current_solution = new_solutioncurrent_fitness = new_fitnessif current_fitness.max() < best_fitness:best_solution = copy.deepcopy(current_solution)best_fitness = current_fitness.max()T *= alphareturn best_solution, best_fitnessparam_grid = {#网格搜索'pop_size': [300, 400, 500],'mutation_rate': [ 0.5, 0.7, 0.9],'T0': [ 1500, 2000],'alpha': [0.95, 0.97, 0.99],'max_iter': [50, 100, 150, 200]
}# 加载数据
J, P = load_data('05.txt')
n, m = J.shape# 初始化最优参数和最优结果
best_params = {}
best_Cmax = float('inf')# 网格搜索循环
for pop_size in param_grid['pop_size']:for mutation_rate in param_grid['mutation_rate']:for T0 in param_grid['T0']:for alpha in param_grid['alpha']:for max_iter in param_grid['max_iter']:print(f'Testing parameters: pop_size={pop_size}, mutation_rate={mutation_rate}, T0={T0}, alpha={alpha}, max_iter={max_iter}')pop = createPop(J, pop_size)Tmax, _, C = decode(J, P, pop[0])fitness = [C.max()]Cmax = C.max()bestInd = copy.deepcopy(pop[0])for i in range(1, pop_size):T_, _, C = decode(J, P, pop[i])if C.max() < Cmax:Tmax = T_Cmax = C.max()bestInd = copy.deepcopy(pop[i])fitness.append(C.max())g = 0gen = n * mwhile g < gen:g += 1newInd = []newFitness = []l = 0while l < pop_size / 2:l += 1tm = roulette_wheel_selection(fitness)l1, l2 = cross(pop[tm], bestInd)T1, _, C1 = decode(J, P, l1)newInd.append(l1)newFitness.append(C1.max())if C1.max() < Cmax:Tmax = T1Cmax = C1.max()bestInd = copy.deepcopy(l1)T2, _, C2 = decode(J, P, l2)newInd.append(l2)newFitness.append(C2.max())if C2.max() < Cmax:Tmax = T2Cmax = C2.max()bestInd = copy.deepcopy(l2)newpop = pop + newIndnewFit = fitness + newFitnessnewId = np.array(newFit).argsort()[:pop_size]pop = copy.deepcopy([newpop[i] for i in newId])fitness = [newFit[i] for i in newId]for i in range(pop_size):pop[i] = mutate(pop[i], mutation_rate)Ind = copy.deepcopy(pop[i])Tt, _, Ct = decode(J, P, Ind)fitness[i] = Ct.max()if Ct.max() < Cmax:Tmax = TtCmax = Ct.max()bestInd = copy.deepcopy(Ind)# 模拟退火for i in range(pop_size):pop[i], fitness[i] = simulated_annealing(pop[i], J, P, T0, alpha, max_iter)if fitness[i] < Cmax:Tmax, _, _ = decode(J, P, pop[i])Cmax = fitness[i]bestInd = copy.deepcopy(pop[i])print(f'第{g}代, Cmax={Cmax}')if Cmax < best_Cmax:best_Cmax = Cmaxbest_params = {'pop_size': pop_size,'mutation_rate': mutation_rate,'T0': T0,'alpha': alpha,'max_iter': max_iter}print(f'Best parameters: {best_params}')
print(f'Best Cmax: {best_Cmax}')# 使用最优参数重新运行算法
pop_size = best_params['pop_size']
mutation_rate = best_params['mutation_rate']
T0 = best_params['T0']
alpha = best_params['alpha']
max_iter = best_params['max_iter']
pop = createPop(J, pop_size)
Tmax, _, C = decode(J, P, pop[0])
fitness = [C.max()]
Cmax = C.max()
bestInd = copy.deepcopy(pop[0])
for i in range(1, pop_size):T_, _, C = decode(J, P, pop[i])if C.max() < Cmax:Tmax = T_Cmax = C.max()bestInd = copy.deepcopy(pop[i])fitness.append(C.max())
g = 0
gen = n * m
chistory = []
while g < gen:g += 1newInd = []newFitness = []l = 0while l < pop_size / 2:l += 1tm = roulette_wheel_selection(fitness)l1, l2 = cross(pop[tm], bestInd)T1, _, C1 = decode(J, P, l1)newInd.append(l1)newFitness.append(C1.max())if C1.max() < Cmax:Tmax = T1Cmax = C1.max()bestInd = copy.deepcopy(l1)T2, _, C2 = decode(J, P, l2)newInd.append(l2)newFitness.append(C2.max())if C2.max() < Cmax:Tmax = T2Cmax = C2.max()bestInd = copy.deepcopy(l2)newpop = pop + newIndnewFit = fitness + newFitnessnewId = np.array(newFit).argsort()[:pop_size]pop = copy.deepcopy([newpop[i] for i in newId])fitness = [newFit[i] for i in newId]for i in range(pop_size):pop[i] = mutate(pop[i], mutation_rate)Ind = copy.deepcopy(pop[i])Tt, _, Ct = decode(J, P, Ind)fitness[i] = Ct.max()if Ct.max() < Cmax:Tmax = TtCmax = Ct.max()bestInd = copy.deepcopy(Ind)# 模拟退火for i in range(pop_size):pop[i], fitness[i] = simulated_annealing(pop[i], J, P, T0, alpha, max_iter)if fitness[i] < Cmax:Tmax, _, _ = decode(J, P, pop[i])Cmax = fitness[i]bestInd = copy.deepcopy(pop[i])print(f'第{g}代, Cmax={Cmax}')chistory.append(Cmax)
plt.plot(chistory)
plt.show()
drawGantt(Tmax)
plt.show()

相关文章:

数学建模学习(111):改进遗传算法(引入模拟退火、轮盘赌和网格搜索)求解JSP问题

文章目录 一、车间调度问题1.1目前处理方法1.2简单案例 二、基于改进遗传算法求解车间调度2.1车间调度背景介绍2.2遗传算法介绍2.2.1基本流程2.2.2遗传算法的基本操作和公式2.2.3遗传算法的优势2.2.4遗传算法的不足 2.3讲解本文思路及代码2.4算法执行结果&#xff1a; 三、本文…...

Golang | Leetcode Golang题解之第241题为运算表达式设计优先级

题目&#xff1a; 题解&#xff1a; const addition, subtraction, multiplication -1, -2, -3func diffWaysToCompute(expression string) []int {ops : []int{}for i, n : 0, len(expression); i < n; {if unicode.IsDigit(rune(expression[i])) {x : 0for ; i < n &…...

Unity客户端接入原生Google支付

Unity客户端接入原生Google支付 1. Google后台配置2. 开始接入Java部分C#部分Lua部分 3. 导出工程打包测试参考踩坑注意 1. Google后台配置 找到内部测试&#xff08;这个测试轨道过审最快&#xff09;&#xff0c;打包上传&#xff0c;这个包不需要接入支付&#xff0c;如果已…...

Spring Cloud之五大组件

Spring Cloud 是一系列框架的有序集合&#xff0c;为开发者提供了快速构建分布式系统的工具。这些组件可以帮助开发者做服务发现&#xff0c;配置管理&#xff0c;负载均衡&#xff0c;断路器&#xff0c;智能路由&#xff0c;微代理&#xff0c;控制总线等。以下是 Spring Cl…...

在 CentOS 7 上安装 Docker 并安装和部署 .NET Core 3.1

1. 安装 Docker 步骤 1.1&#xff1a;更新包索引并安装依赖包 先安装yum的扩展&#xff0c;yum-utils提供了一些额外的工具&#xff0c;这些工具可以执行比基本yum命令更复杂的任务 sudo yum install -y yum-utils sudo yum update -y #更新系统上已安装的所有软件包到最新…...

redis的学习(一):下载安装启动连接

简介 redis的下载&#xff0c;安装&#xff0c;启动&#xff0c;连接使用 nosql nosql&#xff0c;即非关系型数据库&#xff0c;和传统的关系型数据库的对比&#xff1a; sqlnosql数据结构结构化非结构化数据关联关联的非关联的查询方式sql查询非sql查询事务特性acidbase存…...

前端设计模式面试题汇总

面试题 1. 简述对网站重构的理解&#xff1f; 参考回答&#xff1a; 网站重构&#xff1a;在不改变外部行为的前提下&#xff0c;简化结构、添加可读性&#xff0c;而在网站前端保持一致的行为。也就是说是在不改变UI的情况下&#xff0c;对网站进行优化&#xff0c; 在扩展的…...

linux(CentOS、Ubuntu)安装python3.12.2环境

1.下载官网Python安装包 wget https://www.python.org/ftp/python/3.12.2/Python-3.12.2.tar.xz 1.1解压 tar -xf Python-3.12.2.tar.xz 解压完后切换到Python-3.12.2文件夹(这里根据自己解压的文件夹路径) cd /usr/packages/Python-3.12.2/ 1.2升级软件包管理器 CentOS系…...

CSS 中border-radius 属性

border-radius 属性在 CSS 中用于创建圆角边框。它可以接受一到四个值&#xff0c;这些值可以是长度值&#xff08;如像素 px、em 等&#xff09;或百分比&#xff08;%&#xff09;。当提供四个值时&#xff0c;它们分别对应于边框的左上角、右上角、右下角和左下角的圆角半径…...

【大数据专题】数据仓库

1. 简述数据仓库架构 &#xff1f; 数据仓库的核心功能从源系统抽取数据&#xff0c;通过清洗、转换、标准化&#xff0c;将数据加载到BI平台&#xff0c;进而满足业 务用户的数据分析和决策支持。 数据仓库架构包含三个部分&#xff1a;数据架构、应用程序架构、底层设施 1&…...

go关于string与[]byte再学深一点

目标&#xff1a;充分理解string与[]bytes零拷贝转换的实现 先回顾下string与[]byte的基本知识 1. string与[]byte的数据结构 reflect包中关于字符串的数据结构 // StringHeader is the runtime representation of a string.type StringHeader struct {Data uintptrLen int} …...

Qt 实战(7)元对象系统 | 7.4、属性系统:深度解析与应用

文章目录 一、属性系统&#xff1a;深度解析与应用1、定义属性2、属性系统的作用3、属性系统工作原理&#xff08;1&#xff09;Q_PROPERTY宏&#xff08;2&#xff09;moc 的作用&#xff08;3&#xff09;属性在元对象中的注册 4、获取与设置属性4.1、QObject::property()与Q…...

Docker核心技术:容器技术要解决哪些问题

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Docker核心技术 系列文章&#xff1a;容器技术要解决哪些问题&#xff0c;其他文章快捷链接如下&#xff1a; 应用架构演进容器技术要解决哪些问题&#xff08;本文&#xff09;Docker的基本使用Docker是如何实…...

sklearn中的增量学习:特征提取的艺术

sklearn中的增量学习&#xff1a;特征提取的艺术 在机器学习领域&#xff0c;特征提取是构建有效模型的关键步骤。然而&#xff0c;并非所有数据集都适合一次性加载到内存中进行处理&#xff0c;尤其是在处理大规模数据集时。Scikit-learn&#xff08;sklearn&#xff09;提供…...

PostgreSQL 中如何处理数据的唯一性约束?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中如何处理数据的唯一性约束&#xff1f;一、什么是唯一性约束二、为什么要设置唯一性约束…...

VAE论文阅读

在网上看到的VAE解释&#xff0c;发现有两种版本&#xff1a; 按照原来论文中的公式纯数学推导&#xff0c;一般都是了解生成问题的人写的&#xff0c;对小白很不友好。按照实操版本的&#xff0c;非常简单易懂&#xff0c;比如苏神的。但是却忽略了论文中的公式推导&#xff…...

【数据分享】2013-2022年我国省市县三级的逐月SO2数据(excel\shp格式\免费获取)

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2000——2022年的省市县三级的逐月PM2.5数据和2013-2022年的省市县三级的逐月CO数据&#xff08;均可查看之前的文章获悉详情&#xff09;&#xff01; 本次我们分享的是我国2013——2022年的省…...

【Jmeter】记录一次Jmeter实战测试

Jmeter实战 1、需求2、实现2.1、新建线程组2.2、导入参数2.3、新建HTTP请求2.4、添加监听器2.5、结果 1、需求 查询某个接口在高并发场景下的响应时间(loadtime)&#xff0c;需求需要响应在50ms以内&#xff0c;接下来用Jmeter测试一下 Jmeter安装见文章《Jemeter安装教程&am…...

volatile,最轻量的同步机制

目录 一、volatile 二、如何使用&#xff1f; 三、volatile关键字能代替synchronized关键字吗&#xff1f; 四、总结&#xff1a; 还是老样子&#xff0c;先来看一段代码&#xff1a; 我们先由我们自己的常规思路分析一下代码&#xff1a;子线程中&#xff0c;一直循环&…...

在Linux、Windows和macOS上释放IP地址并重新获取新IP地址的方法

文章目录 LinuxWindowsmacOS 在Linux、Windows和macOS上释放IP地址并重新获取新IP地址的方法各有不同。以下是针对每种操作系统的详细步骤&#xff1a; Linux 使用DHCP客户端&#xff1a;大多数Linux发行版都使用DHCP&#xff08;动态主机配置协议&#xff09;来自动获取IP地址…...

Mamba-yolo|结合Mamba注意力机制的视觉检测

一、本文介绍 PDF地址&#xff1a;https://arxiv.org/pdf/2405.16605v1 代码地址&#xff1a;GitHub - LeapLabTHU/MLLA: Official repository of MLLA Demystify Mamba in Vision: A Linear AttentionPerspective一文中引入Baseline Mamba&#xff0c;指明Mamba在处理各种高…...

语音识别标记语言(SSML):自动标识中文多音字

好的&#xff0c;以下是完整的实现代码&#xff0c;包括导入库、分词、获取拼音和生成 SSML 标记的全过程&#xff1a; import thulac from pypinyin import pinyin, Style# 初始化 THULAC thu1 thulac.thulac(seg_onlyTrue)# 测试文本 text "银行行长正在走行。"…...

排序算法与复杂度介绍

1. 排序算法 1.1 排序算法介绍 排序也成排序算法&#xff08;Sort Algorithm&#xff09;&#xff0c;排序是将一组数据&#xff0c;依照指定的顺序进行排序的过程 1.2 排序的分类 1、内部排序&#xff1a; 指将需要处理的所有数据都加载到**内部存储器&#xff08;内存&am…...

Kafka介绍及Go操作kafka详解

文章目录 Kafka介绍及Go操作kafka详解项目背景解决方案面临的问题业界方案ELKELK方案的问题日志收集系统架构设计架构设计组件介绍将学到的技能消息队列的通信模型点对点模式 queue发布/订阅 topicKafka介绍Kafka的架构图工作流程选择partition的原则ACK应答机制Topic和数据日志…...

DAY05 CSS

文章目录 1 CSS选择器(Selectors)8. 后代(包含)选择器9. 直接子代选择器10. 兄弟选择器11. 相邻兄弟选择器12. 属性选择器 2 伪元素3 CSS样式优先级1. 相同选择器不同样式2. 相同选择器相同样式3. 继承现象4. 选择器不同权值的计算 4 CSS中的值和单位1. 颜色表示法2. 尺寸表示法…...

HTTPS 的加密过程 详解

HTTP 由于是明文传输&#xff0c;所以安全上存在以下三个风险&#xff1a; 窃听风险&#xff0c;比如通信链路上可以获取通信内容。篡改风险&#xff0c;比如通信内容被篡改。冒充风险&#xff0c;比如冒充网站。 HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议&#xff0c…...

spring整合mybatis,junit纯注解开发(包括连接druid报错的所有解决方法)

目录 Spring整合mybatis开发步骤 第一步&#xff1a;创建我们的数据表 第二步&#xff1a;编写对应的实体类 第三步&#xff1a;在pom.xml中导入我们所需要的坐标 spring所依赖的坐标 mybatis所依赖的坐标 druid数据源坐标 数据库驱动依赖 第四步&#xff1a;编写SpringC…...

ClusterIP、NodePort、LoadBalancer 和 ExternalName

Service 定义 在 Kubernetes 中&#xff0c;由于Pod 是有生命周期的&#xff0c;如果 Pod 重启它的 IP 可能会发生变化以及升级的时候会重建 Pod&#xff0c;我们需要 Service 服务去动态的关联这些 Pod 的 IP 和端口&#xff0c;从而使我们前端用户访问不受后端变更的干扰。 …...

【Day1415】Bean管理、SpringBoot 原理、总结、Maven 高级

0 SpringBoot 配置优先级 从上到下 虽然 springboot 支持多种格式配置文件&#xff0c;但是在项目开发时&#xff0c;推荐统一使用一种格式的配置 &#xff08;yml是主流&#xff09; 1 Bean管理 1.1 从 IOC 容器中获取 Bean 1.2 Bean 作品域 可以通过注解 Scope("proto…...

Git之repo sync -c与repo sync -dc用法区别(四十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…...

vite + vue3 + uniapp 项目从零搭建

vite + vue3 + uniapp 项目从零搭建 1、创建项目1.1、创建Vue3/vite版Uniapp项目1.2、安装依赖1.3、运行项目2、弹出 用户隐私保护提示 方法2.1、更新用户隐私保护指引 和 修改配置文件2.2、授权结果处理方法3、修改`App.vue`文件内容4、处理报`[plugin:uni:mp-using-component…...

在CentOS中配置三个节点之间相互SSH免密登陆

在CentOS中配置三个节点&#xff08;假设分别为node1、node2、node3&#xff09;两两之间相互SSH免密登陆&#xff0c;可以按照以下步骤进行&#xff1a; 一、生成密钥对 在所有节点上生成密钥对&#xff1a; 在每个节点&#xff08;node1、node2、node3&#xff09;上执行以…...

arm 内联汇编基础

一、 Arm架构寄存器体系熟悉 基于arm neon 实现的代码有 intrinsic 和inline assembly 两种实现。 1.1 通用寄存器 arm v7 有 16 个 32-bit 通用寄存器&#xff0c;用 r0-r15 表示。 arm v8 有 31 个 64-bit 通用寄存器&#xff0c;用 x0-x30 表示&#xff0c;和 v7 不一样…...

Java语言程序设计——篇五(1)

数组 概述数组定义实例展示实战演练 二维数组定义数组元素的使用数组初始化器实战演练&#xff1a;矩阵计算 &#x1f4ab;不规则二维数组实战演练&#xff1a;杨辉三角形 概述 ⚡️数组是相同数据类型的元素集合。各元素是有先后顺序的&#xff0c;它们在内存中按照这个先后顺…...

【香橙派开发板测试】:在黑科技Orange Pi AIpro部署YOLOv8深度学习纤维分割检测模型

文章目录 &#x1f680;&#x1f680;&#x1f680;前言一、1️⃣ Orange Pi AIpro开发板相关介绍1.1 &#x1f393; 核心配置1.2 ✨开发板接口详情图1.3 ⭐️开箱展示 二、2️⃣配置开发板详细教程2.1 &#x1f393; 烧录镜像系统2.2 ✨配置网络2.3 ⭐️使用SSH连接主板 三、…...

集成学习在数学建模中的应用

集成学习在数学建模中的应用 一、集成学习概述&#xff08;一&#xff09;基知&#xff08;二&#xff09;相关术语&#xff08;三&#xff09;集成学习为何能提高性能&#xff1f;&#xff08;四&#xff09;集成学习方法 二、Bagging方法&#xff08;一&#xff09;装袋&…...

WebKit 的 Web SQL 数据库:现代浏览器的本地存储解决方案

WebKit 的 Web SQL 数据库&#xff1a;现代浏览器的本地存储解决方案 随着Web应用的不断发展&#xff0c;对本地存储的需求也日益增加。WebKit作为许多现代浏览器的核心引擎&#xff0c;提供了一种强大的本地存储解决方案&#xff1a;Web SQL 数据库。本文将详细探讨Web SQL 数…...

Yolo-World网络模型结构及原理分析(三)——RepVL-PAN

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1. 网络结构2. 特征融合3. 文本引导&#xff08;Text-guided&#xff09;4. 图像池化注意力&#xff08;Image-Pooling Attention&#xff09;5. 区域文本匹配&…...

代码随想录——一和零(Leetcode474)

题目链接 0-1背包 class Solution {public int findMaxForm(String[] strs, int m, int n) {// 本题m&#xff0c;n为背包两个维度// dp[i][j]:最多右i个0和j个1的strs的最大子集大小int[][] dp new int[m 1][n 1];// 遍历strs中字符串for(String str : strs){int num0 …...

力扣题解(组合总和IV)

377. 组合总和 Ⅳ 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 思路&#xff1a; 本题实质上是给一些数字&#xff0c;让他们在满足和是targ…...

Postgresql主键自增的方法

Postgresql主键自增的方法 一.方法&#xff08;一&#xff09; 使用 serial PRIMARY KEY 插入数据 二.方法&#xff08;二&#xff09; &#x1f388;边走、边悟&#x1f388;迟早会好 一.方法&#xff08;一&#xff09; 使用 serial PRIMARY KEY 建表语句如下&#xf…...

【源码阅读】Sony的go breaker熔断器源码探究

文章目录 背景源码分析总结 背景 在微服务时代&#xff0c;服务和服务之间调用、跨部门调用都是很常见的事&#xff0c;但这些调用都存在很多不确定因素&#xff0c;如核心服务A依赖的部门B服务挂掉了&#xff0c;那么A本身的功能将会受到直接的影响&#xff0c;而这些都会影响…...

LeetCode题(66,69,35,88)--《c++》

66.加一 // // Created by wxj05 on 2024/7/20. // //法一 class Solution { public:vector<int> plusOne(vector<int>& digits) {bool carry true; // 进位标志for (int i digits.size() - 1; i > 0 && carry; --i) {digits[i] 1;carry digit…...

来参与“向日葵杯”全国教育仿真技术大赛~

可点击进行了解&#xff1a;“向日葵杯”全国教育仿真技术大赛 (sunmooc.cn) 本次大赛共分为四个赛道&#xff1a;自主命题赛道、教育知识图谱设计赛道、FPGA硬件扑克牌对抗赛道、EasyAR元宇宙空间设计赛道。 参赛对象 &#xff1a; 具有正式学籍的在校研究生&#xff0c;本科…...

SQL每日一题:删除重复电子邮箱

题干 表: Person -------------------- | Column Name | Type | -------------------- | id | int | | email | varchar | -------------------- id 是该表的主键列(具有唯一值的列)。 该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。 编写解决方案 删除 所有重复…...

3、宠物商店智能合约实战(truffle智能合约项目实战)

3、宠物商店智能合约实战&#xff08;truffle智能合约项目实战&#xff09; 1-宠物商店环境搭建、运行2-webjs与宠物逻辑实现3-领养智能合约初始化4-宠物领养实现5-更新宠物领养状态 1-宠物商店环境搭建、运行 https://www.trufflesuite.com/boxes/pet-shop 这个还是不行 或者…...

数据库系列

目录 一、数据库的概念和作用 1.数据库的特点 2.数据模型 二、数据库系统 1.数据库管理系统 2.数据库的基本操作 一、数据库的概念和作用 数据库是指长期存储在计算机内&#xff0c;有组织的、可共享的数据集合。它可视为一个电子化的文件柜&#xff0c;用来存储电子文件…...

极狐GitLab如何启用和配置PlantUML?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…...

Shell 构建flutter + Android 生成Apk

具体步骤 #shell 具体实现和说明如下: echo "build_start_apk!" echo "编译此脚本的前提条件如下:" #在Android 项目的主工程下,进入主工程文件夹,创建build-android 文件夹,在其文件夹下有build-android.sh文件,此文件就是整个文章的脚本内容(…...

如何用手机压缩视频?手机压缩视频方法来了

高清视频的大文件大小常常成为分享和存储的障碍&#xff0c;尤其是在数据流量有限或存储空间紧张的情况下。幸运的是&#xff0c;无论是智能手机还是个人电脑&#xff0c;都有多种方法可以帮助我们轻松压缩视频文件&#xff0c;以适应不同的需求和情境。本文将介绍如何在手机上…...