JSP ft06 问题几个求解思路整理

刷到这篇文章使用Q-learning去求接JSP ft06 问题用基本Q-learning解决作业车间调度问题(JSP),以FT06案例为例_q-learning算法在车间调度-CSDN博客

本着贼不走空的原则打算全部copy到本地试下,文章作者使用的tf06.txt在这里获取

https://web.cecs.pdx.edu/bart/cs510ss/project/jobshop/jobshop/ft06.txt

6 6
2 1 0 3 1 6 3 7 5 3 4 6
1 8 2 5 4 10 5 10 0 10 3 4
2 5 3 4 5 8 0 9 1 1 4 7
1 5 0 5 2 5 3 3 4 8 5 9
2 9 1 3 4 5 5 4 0 3 3 1
1 3 3 3 5 9 0 10 4 4 2 1

FT06 是什么问题

FT06 数据文件通常用于调度问题,特别是在作业车间调度(Job Shop Scheduling)中。根据你提供的数据格式,下面是对 ft06.txt 文件内容的详细解释:

文件结构

第一行:6 6 这行表示有 6 个作业(Jobs)和 6 个操作(Operations)。在 FT06 的情况下,作业和操作的数量相等。

接下来的几行是作业的调度信息,通常每行代表一个作业在不同机器上的操作时间。

数据解析

每一行的结构如下:

2  1  0  3  1  6  3  7  5  3  4  6
  • 每行中的数字表示该作业在不同机器上的操作时间。

上面例子表示

  • 2 1:表示工件的第一个操作需要在机器 2 上进行,且该操作的加工时间为 1。
  • 0 3:表示工件的第二个操作需要在机器 0 上进行,且该操作的加工时间为 3。
  • 1 6:表示工件的第三个操作需要在机器 1 上进行,且该操作的加工时间为 6。
  • 3 7:表示工件的第四个操作需要在机器 3 上进行,且该操作的加工时间为 7。
  • 5 3:表示工件的第五个操作需要在机器 5 上进行,且该操作的加工时间为 3。
  • 4 6:表示工件的第六个操作需要在机器 4 上进行,且该操作的加工时间为 6。


目标

FT06 的目标是最小化所有作业的完成时间(makespan)或其他调度指标,如总延迟、最大延迟等。执行代码

执行完成后打印

工件顺序列表: [5, 0, 5, 1, 0, 0, 0, 2, 4, 4, 0, 5, 5, 0, 4, 4, 1, 1, 1, 1, 1, 2, 3, 3, 2, 5, 2, 2, 2, 5, 3, 3, 3, 4, 3, 4]
各工序完工时间: [

[1, 4, 17, 24, 27, 33],

[11, 20, 48, 58, 68, 72],

[6, 76, 84, 93, 94, 101],

[25, 73, 78, 81, 109, 118],

[15, 20, 38, 42, 96, 97],

[3, 6, 36, 46, 52, 53]]
开始时间列表:

[0, 0, 3, 3, 1, 11, 17, 1, 6, 17, 24, 27, 36, 27, 33, 38, 15, 38, 48, 58, 68, 72, 20, 68, 76, 48, 84, 93, 94, 52, 73, 78, 101, 93, 109, 96]

文章作者也说算法实在不断收敛的,但是最终和FT06案例的最优解(55)还有很大的差距,这是因为对于动作空间的设计太过简单,而且没有将机器的空闲时间利用起来,同一机器前后工序间的空闲时间太大,导致调度效果不理想。

遗传算法

知乎上看到这篇使用遗传算法求接的帖子

https://zhuanlan.zhihu.com/p/684600755

import numpy as np
import matplotlib.pyplot as plt
import random
import copy
import random

def createInd(J):
    '''
    初始化操作,一次初始化一个个体,机器矩阵从1开始
    J: 机器顺序矩阵,J[i, j]表示加工i工件的第j个操作的机器号。大小为n*m
    T: 加工时间矩阵,T[i, j]表示工件j再机器i上的加工时间。大小为m*n
    '''
    n = J.shape[0]  # 工件数
    # m = J.shape[1]  # 机器数
    s = []
    Ji = J.copy()
    while not np.all(Ji == 0):
        I = np.random.randint(0, n)
        M = Ji[I, 0]
        if M != 0:
            s.append(I)
            b = np.roll(Ji[I, :], -1)
            b[-1] = 0
            Ji[I, :] = b
    return s

def decode(J, P, s):
    """
    function:
    JSP解码函数,用于计算C_max和生成甘特图。

    parameter:
    - J: 机器顺序矩阵,J[i, j]表示加工i工件的第j个操作的机器号。
    - P: 加工时间矩阵,P[i, j]表示工件i在机器j上的加工时间。
    - s: 待解码的序列。

    return:
    - T: 甘特图矩阵。
    - M: 工件排列矩阵。
    - C: 完工时间矩阵。
    """
    n, m = J.shape
    T = [[[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]] - 1
        process_time = P[job, k[job]]
        last_job_finish = C[job, k[job] - 1] if k[job] > 0 else 0

        # 寻找机器上的第一个合适空闲时间段
        start_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(T[machine][i - 1][-1], last_job_finish)
            gap_end = T[machine][i][0]
            if gap_end - gap_start >= process_time:
                start_time = gap_start  # 找到合适的起始时间
                insert_index = i  # 更新插入位置
                break

        end_time = start_time + process_time
        C[job, k[job]] = end_time
        T[machine].insert(insert_index, [start_time, job, k[job], end_time])
        k[job] += 1

    # 根据T矩阵构建M矩阵
    M = [[] for _ in range(m)]
    for machine in range(m):
        for entry in T[machine][1:]:
            M[machine].append(entry[1])  # 工件号

    return T, M, C

def drawGantt(timeList):
    T = timeList.copy()
    # 创建一个新的图形
    plt.rcParams['font.sans-serif'] = ['SimHei']
    fig, ax = plt.subplots(figsize=(10, 6))

    # 颜色映射字典,为每个工件分配一个唯一的颜色
    color_map = {}
    for machine_schedule in T:
        for task_data in machine_schedule[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_data
            color = 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)

    # 设置Y轴标签为机器名称
    ax.set_yticks(range(len(T)))
    ax.set_yticklabels([f'Machine {i+1}' for i in range(len(T))])

    # 设置X轴标签
    plt.xlabel("时间")

    # 添加标题
    plt.title("JSP问题甘特图")

    # 创建图例,显示工件颜色
    legend_handles = []
    for job_idx, color in color_map.items():
        legend_handles.append(plt.Rectangle((0, 0), 1, 1, color=color, label=f'Job {job_idx}'))
    plt.legend(handles=legend_handles, title='工件')

    # # 显示图形
    # plt.show()

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

def cross(A, B):
    '''
    A, B是两个相同长度的list,该函数用于交叉两个list,然后返回两个新的list
    '''
    n = len(A)
    r1 = np.random.randint(n)
    r2 = np.random.randint(n)
#     r1, r2 = 3, 1
    rl, rr = min(r1, r2), max(r1, r2)
    if rl == rr:
        return A, B
    # for A
    bt = copy.deepcopy(B)
    afinal = copy.deepcopy(A)
    for i in range(rl, rr+1):
        bt.remove(A[i])
    k = 0
    for i in range(n):
        if i < rl or i > rr:
            afinal[i] = bt[k]
            k += 1
    # for B
#     print(A, B)
    at = copy.deepcopy(A)
    bfinal = copy.deepcopy(B)
    for i in range(rl, rr+1):
        at.remove(B[i])
    k = 0
    for i in range(n):
        if i < rl or i > rr:
            bfinal[i] = at[k]
            k += 1
    return afinal, bfinal

def load_data(path):
    # 从文本文件读取数据
    with open(path, 'r') as file:
        lines = file.readlines()

    # 解析工件数和机器数
    workpiece, machines = map(int, lines[0].split())

    # 初始化 J 和 P 数组
    J = np.zeros((workpiece, len(lines[1].split()) // 2), dtype=int)
    P = np.zeros((workpiece, len(lines[1].split()) // 2), dtype=int)

    # 解析机器编号和加工时间
    '''
    偶数索引(机器编号):
    J[i - 1][j // 2] = data[j] + 1:机器编号存储在 J 中。因为机器编号可能从 1 开始(如机器1、机器2),在存储时加1,以确保在后续计算中与 Python 的 0 索引保持一致。
i - 1 是当前工件的索引(因为 i 从 1 开始)。
j // 2 将偶数索引映射到 J 的列索引。
奇数索引(加工时间):
P[i - 1][j // 2] = data[j]:加工时间直接存储在 P 中,j // 2 同样用于映射到 P 的列索引。
    '''
    for i in range(1, len(lines)):
        data = list(map(int, lines[i].split()))
        # print(data)
        for j in range(len(data)):
            if j % 2 == 0:
                J[i - 1][j // 2] = data[j]+1
            else:
                P[i - 1][j // 2] = data[j]
    return J, P


if __name__ == '__main__':
    
    J, P = load_data('../jsp_q_learning/FT06.txt')
    n = J.shape[0]  # 工件数
    m = J.shape[1]  # 机器数
    pop_size = 40
    gen = n*m
    pop = createPop(J, pop_size)
    Tmax, _, C = decode(J, P, pop[0])
    fitness = [C.max()]
    Cmax = C.max()
    bestID = 0
    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
    chistory = []
    while g < gen:
        g += 1
        # 所有个体的交叉操作
        l = 0
        newInd = []
        newFitness = []
        while l < pop_size/2:
            tm = np.random.randint(pop_size)       # 随机一个与最优个体交叉
            I1, I2 = cross(pop[tm], bestInd)
            T1, _, C1 = decode(J, P, I1)    # 对交叉后的解码
            newInd.append(I1)               # 交叉后的个体添加入newInd
            newFitness.append(C1.max())     # 交叉后的适应度添加入newFitness
            if C1.max() < Cmax:             # 如果适应度比已知最优个体还好
                Cmax = C1.max()             # 更新最佳适应度
                Tmax = T1                   # 更新最优调度
                bestInd = copy.deepcopy(I1)               # 更新最优个体
            T2, _, C2 = decode(J, P, I2)
            newInd.append(I2)
            newFitness.append(C2.max())
            if C2.max() < Cmax:
                Cmax = C2.max()
                Tmax = T2
                bestInd = copy.deepcopy(I2)
            l += 1
        newpop = pop + newInd               # 交叉后的种群与原来种群合并
        newFit = fitness + newFitness       # 适应度也合并
        newId = np.array(newFit).argsort()[:pop_size]   # 取最好的40个的ID
        pop = copy.deepcopy([newpop[i] for i in newId])
        fitness = [newFit[i] for i in newId]
        # 变异操作
        for i in range(pop_size):
            index1, index2 = random.sample(range(n*m), 2)
            pop[i][index1], pop[i][index2] = pop[i][index2], pop[i][index1]
            Ind = copy.deepcopy(pop[i])
            Tt, _, Ct = decode(J, P, Ind)
            fitness[i] = Ct.max()
            if Ct.max() < Cmax:
                Cmax = Ct.max()
                Tmax = Tt
                bestInd = Ind
        print('第{}代,Cmax={}'.format(g, Cmax))
        wait_time = 0
        for i in Tmax:
            for j in range(1, len(i)):
                wait_time += i[j][0] - i[j-1][-1]
        print('第{}代,平均机器等待时间={}'.format(g, (Cmax*m - J.sum())/m))
        chistory.append(Cmax)

    index = chistory.index(Cmax)
    print(f"{Cmax}首次出现的索引是:{index}")

    print(Tmax)
    print(decode(J, P, bestInd)[1])
    plt.plot(chistory)
    drawGantt(Tmax)
    plt.show()

createInd 函数用于初始化遗传算法中的一个个体(解)

J:一个机器顺序矩阵,形状为 n*m,其中 J[i, j] 表示工件 i 在第 j 个操作中所需的机器号。

通过 J.shape[0] 获取工件的数量 n

  • s 是一个空列表,用于存储生成的个体(即工件的顺序)。
  • JiJ 的副本,用于在后续处理中修改原始的数据而不影响它。
  • 进入一个循环,直到 Ji 中的所有元素都变为0。这个条件确保了所有工件的操作都被处理。随机选择一个工件 I(在 0n-1 之间),并获取该工件当前第一个操作所需的机器号 M
if M != 0:
    s.append(I)
    b = np.roll(Ji[I, :], -1)
    b[-1] = 0
    Ji[I, :] = b

如果机器号 M 不为0(意味着该工件还有未完成的操作)则:

  • 将工件 I 添加到个体列表 s 中。
  • 使用 np.roll 将工件 I 的操作顺序向左滚动,最前面的操作被移到最后,最后一个操作的机器号设置为0,表示该操作已完成。
  • 更新 Ji,反映该工件的操作顺序已经更新。

代码流程署里下

1. 数据加载与初始化

J, P = load_data('../jsp_q_learning/ft06.txt')
n = J.shape[0]  # 工件数
m = J.shape[1]  # 机器数
pop_size = 40
gen = n * m
pop = createPop(J, pop_size)
  • load_data:从指定文件加载工件和机器的数据。
  • nm:分别代表工件数量和机器数量。
  • pop_size:设定种群大小为40。
  • gen:设定最大代数(生成数),为工件数与机器数的乘积。
  • createPop:生成初始种群。

2. 解码与适应度评估

Tmax, _, C = decode(J, P, pop[0])
fitness = [C.max()]
Cmax = C.max()
bestID = 0
bestInd = copy.deepcopy(pop[0])
  • decode:对种群中的个体进行解码,得到调度安排 Tmax 和完成时间 C
  • fitness:记录种群中第一个个体的适应度。
  • Cmax:更新当前的最大完成时间。
  • bestInd:记录当前最优个体。

3. 评估种群中的其他个体

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())
  • 遍历种群中的所有个体,解码并计算适应度,更新最优个体和最大适应度。

4. 迭代优化过程

g = 0
chistory = []
while g < gen:
    g += 1
    # 所有个体的交叉操作
    l = 0
    newInd = []
    newFitness = []
    while l < pop_size/2:
        tm = np.random.randint(pop_size)       # 随机一个与最优个体交叉
        I1, I2 = cross(pop[tm], bestInd)
        ...
        l += 1
  • while g < gen:进行代数迭代,直到达到设定的最大代数。
  • 在内部循环中,进行交叉操作,生成新个体。

5. 交叉与适应度更新

newpop = pop + newInd               # 交叉后的种群与原来种群合并
newFit = fitness + newFitness       # 适应度也合并
newId = np.array(newFit).argsort()[:pop_size]   # 取最好的40个的ID
pop = copy.deepcopy([newpop[i] for i in newId])
fitness = [newFit[i] for i in newId]
  • 将原种群和新生成的个体合并,并更新种群为适应度最好的40个个体。

6. 变异操作

for i in range(pop_size):
    index1, index2 = random.sample(range(n*m), 2)
    pop[i][index1], pop[i][index2] = pop[i][index2], pop[i][index1]
    Ind = copy.deepcopy(pop[i])
    Tt, _, Ct = decode(J, P, Ind)
    fitness[i] = Ct.max()
    if Ct.max() < Cmax:
        Cmax = Ct.max()
        Tmax = Tt
        bestInd = Ind
  • 对每个个体进行变异(交换两个随机位置的工件),并解码更新适应度。

7. 输出当前代信息

print('第{}代,Cmax={}'.format(g, Cmax))
wait_time = 0
for i in Tmax:
    for j in range(1, len(i)):
        wait_time += i[j][0] - i[j-1][-1]
print('第{}代,平均机器等待时间={}'.format(g, (Cmax*m - J.sum())/m))
chistory.append(Cmax)
  • 输出当前代的最大完成时间和平均机器等待时间。

8. 记录最优结果

index = chistory.index(Cmax)
print(f"{Cmax}首次出现的索引是:{index}")

他使用上面代码经过两代变异就找到了最优

第1代,Cmax=60.0
第1代,平均机器等待时间=39.0
第2代,Cmax=55.0
第2代,平均机器等待时间=34.0

最近逛codewithpage时发现了一篇论文https://arxiv.org/pdf/2201.00548v1

在txyz上进行阅读理解

全文总结

这篇论文提出了一个通用框架,使用强化学习(RL)来解决动态车间调度问题(DJSP)。该框架的关键方面包括:(1) 将DJSP表述为马尔可夫决策过程,其中以析取图为状态,以通用调度规则为动作;(2) 使用注意力机制进行图表示学习,以从状态中提取特征;以及(3) 采用带有优先级回放和噪声网络的双重对抗深度Q网络(D3QPN)作为RL算法。作者还引入了一个名为Gymjsp的新基准,以促进基于RL的DJSP研究。该提出的框架旨在提供一种通用有效的DJSP解决方案,将结构化的人类知识(调度规则)与数据驱动的RL智能相结合。

主要观点

  • 将DJSP公式化为马尔可夫决策过程,其中离散图为状态,通用调度规则为动作
  • 使用注意力机制进行图表示学习,从状态中提取特征
  • 采用双重对抗深度Q网络(D3QPN)作为强化学习算法,包括优先级回放和噪声网络
  • 引入一个新的基准测试环境Gymjsp,以促进基于强化学习的DJSP研究
  • 旨在提供一种灵活有效的DJSP解决方案,结合结构化的人类知识(调度规则)和数据驱动的强化学习智能

找到对那个的代码

GitHub - Yunhui1998/Gymjsp: Share a benchmark that can easily apply reinforcement learning in Job-shop-scheduling

里面恰好有个例子是针对ft06 作业的,跑一下自动生成甘特图

import os
os.sys.path.insert(0, '../gymjsp')
from gymjsp.jsspenv import HeuristicAttentionJsspEnv

env = HeuristicAttentionJsspEnv('ft06', schedule_cycle=10)
env.reset()

for _ in range(10000):
    env.step(env.action_space.sample())

env.render()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/911229.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Uniapp安装Pinia并持久化(Vue3)

安装pinia 在uni-app的Vue3版本中&#xff0c;Pinia已被内置&#xff0c;无需额外安装即可直接使用&#xff08;Vue2版本则内置了Vuex&#xff09;。 HBuilder X项目&#xff1a;直接使用&#xff0c;无需安装。CLI项目&#xff1a;需手动安装&#xff0c;执行yarn add pinia…

Template Method(模板方法)

1)意图 定义一个操作中的算法骨架&#xff0c;而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 2)结构 模板方法模式的结构图如图7-47 所示。 其中: AbstractClass(抽象类) 定义抽象的原语操作&#xff0c;具体…

无人机场景数据集大全「包含数据标注+划分脚本+训练脚本」 (持续原地更新)

一、作者介绍&#xff1a;六年算法开发经验、AI 算法经理、阿里云专家博主。擅长&#xff1a;检测、分割、理解、AIGC 等算法训练与推理部署任务。 二、数据集介绍&#xff1a; 质量高&#xff1a;高质量图片、高质量标注数据&#xff0c;使用 labelimg 软件吐血标注、整理&…

安当ASP系统:适合中小企业的轻量级Radius认证服务器

安当ASP&#xff08;Authentication Service Platform&#xff09;身份认证系统是一款功能强大的身份认证服务平台&#xff0c;特别适用于中小企业。其中&#xff0c;简约型Radius认证服务器是安当ASP系统中的一个重要组成部分。以下是对该系统的详细介绍&#xff1a; 一、主要…

跨域及解决跨域

什么是跨域 前端与后端不在同一个域名下&#xff1a; 解决 import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component;import java.io.IOException…

关于解决DICOM文件中中文乱码问题的解决方案

目录 问题背景 常见字符集和编码 DICOM标准中的字符集支持 解决方案 示例代码 处理不同字符集的示例 关键点 注意事项 结论 在解析DICOM文件时,如果字符集处理不当,可能会出现中文乱码的问题。本文将介绍如何正确处理DICOM文件中的字符集,以避免乱码问题。DICOM文件…

6.机器学习--PCA主成分分析(降维)

目录 1.问题的引入 为什么要降维&#xff1f; 降维的好处 降维的本质 2.降维的主要方法&#xff1a; 2.1 特征选择 2.2 特征抽取 3.主成分分析&#xff08;PCA&#xff09;推导 3.1.向量的表示及基变换 3.2.协方差矩阵及优化目标 3.3.算法及实例 3.4.实例 3.5.代…

我们来学mysql -- 同时使用 AND 和 OR 查询错误(填坑篇)

AND 和 OR 一同使用问题 现象分析处理扩展 现象 业务上在“锁定”当前零件所在出口国的所有零件时&#xff0c;出现其他国家零件 问题定位 分析 or 切断了操作符之间的连续性&#xff0c;从union角度分析 where k1 Td621 and k1 Vda96 or k3 P00009等同 select * fr…

基于Zynq FPGA的雷龙SD NAND存储芯片性能测试

文章目录 前言一、SD NAND特征1.1 SD卡简介1.2 SD卡Block图 二、SD卡样片三、Zynq测试平台搭建3.1 测试流程3.2 SOC搭建 四、软件搭建五、测试结果六、总结 前言 随着嵌入式系统和物联网设备的快速发展&#xff0c;高效可靠的存储解决方案变得越来越重要。雷龙发展推出的SD NA…

vscode翻译插件

vscode翻译插件 需求 &#xff1a; 在编写代码的时候&#xff0c; 打印或者定义变量的时候总是想不起来英文名称&#xff0c; 所有就开发了一款中文转换为英文的插件。 功能 1、目前支持选中中文&#xff0c;右键选择打印或者变量进行转换。 2、目前支持选中中文&#xff0…

信息安全工程师(81)网络安全测评质量管理与标准

一、网络安全测评质量管理 遵循标准和流程 网络安全测评应严格遵循国家相关标准和流程&#xff0c;确保测评工作的规范性和一致性。这些标准和流程通常包括测评方法、测评步骤、测评指标等&#xff0c;为测评工作提供明确的指导和依据。 选择合格的测评团队 测评团队应具备相关…

【C++】lambda表达式的理解与运用(C++11新特性)

&#x1f308; 个人主页&#xff1a;谁在夜里看海. &#x1f525; 个人专栏&#xff1a;《C系列》《Linux系列》 ⛰️ 天高地阔&#xff0c;欲往观之。 目录 前言 C11之前的例子 一、lambda的语法 lambda函数示例&#xff1a; 二、lambda的捕获列表 1.传值捕获 mutable修饰 2.…

K8s资源对象监控之kube-state-metrics详解(Detailed Explanation of Kube State Metrics)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

儿童安全座椅行业全面深入分析

儿童安全座椅就是一种专为不同体重&#xff08;或年龄段&#xff09;的儿童设计&#xff0c;将孩子束缚在安全座椅内&#xff0c;能有效提高儿童乘车安全的座椅。欧洲强制性执行标准ECE R44/03的定义是&#xff1a;能够固定到机动车辆上&#xff0c;带有ISOFIX接口、LATCH接口的…

传输协议设计与牧村摆动(Makimoto‘s Wave)

有一条活鱼和一条死鱼&#xff0c;你准备怎么做&#xff0c;你会将活鱼红烧或将死鱼清蒸吗&#xff1f;好的食材只需要最简单的烹饪&#xff0c;不好的食材才需要花活儿。 我此前的文字几乎都在阐述一个观点&#xff0c;广域网就是那条死鱼&#xff0c;数据中心则是那条活鱼。…

【极限编程(XP)】

极限编程&#xff08;XP&#xff09;简介 定义与核心价值观&#xff1a;极限编程&#xff08;Extreme Programming&#xff0c;XP&#xff09;是一种轻量级、敏捷的软件开发方法。它强调团队合作、客户参与、持续测试和快速反馈等价值观&#xff0c;旨在提高软件开发的效率和质…

Autosar CP 内存抽象接口MemIf规范导读

一、MemIf规范概述 内存抽象接口(Memory Abstraction Interface,简称MemIf)是AUTOSAR架构中用于访问和管理非易失性随机存取存储器(NVRAM)的重要组成部分。以下是对MemIf的详细概述: 1. 功能和目的 MemIf的主要功能是为上层软件(如NVRAM管理器)提供统一的接口,以便…

动态规划 —— dp 问题-粉刷房子

1. 剑指offer —— 粉刷房子 题目链接&#xff1a; LCR 091. 粉刷房子 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/JEj789/description/ 2. 题目解析 根据上图可以得到costs横坐标&#xff08;行&#xff09;是房子的号数&#xff0c;红色的下标是0&…

将vscode的终端改为cygwin terminal

现在终端是默认的power shell&#xff0c;没有显示cygwin 接下来选择默认配置文件 找到cygwin的选项即可 然后提示可能不安全什么的&#xff0c;点是&#xff0c;就有了

Scala的包及其导入

//1.单个导入 //import com.sala02.A //import com.sala02.B//2.导入多个类 //import com.sala02.{A,B}//3.导入一个包下的所有类&#xff1a;包名._ //import com.sala02._//4.导入一个包中的类&#xff0c;给他改个名字 //格式&#xff1a;import 包名.{原来的名字 > 新名…