基于Python实现的遗传算法求TSP问题

news/2024/5/4 4:24:07/文章来源:https://blog.csdn.net/sheziqiong/article/details/126803212

遗传算法求TSP问题
目录
人工智能第四次实验报告 1
遗传算法求TSP问题 1
一 、问题背景 1
1.1 遗传算法简介 1
1.2 遗传算法基本要素 2
1.3 遗传算法一般步骤 2
二 、程序说明 3
2.3 选择初始群体 4
2.4 适应度函数 4
2.5 遗传操作 4
2.6 迭代过程 4
三 、程序测试 5
3.1 求解不同规模的TSP问题的算法性能 5
3.2 种群规模对算法结果的影响 5
3.3 交叉概率对算法结果的影响 6
3.4 变异概率对算法结果的影响 7
3.5 交叉概率和变异概率对算法结果的影响 7
四 、算法改进 8
4.1 块逆转变异策略 8
4.2 锦标赛选择法 9
五 、实验总结 10
一 、问题背景
1.1遗传算法简介
遗传算法是一种进化算法,基于自然选择和生物遗传等生物进化机制的一种搜索算法,其通过选 择、重组和变异三种操作实现优化问题的求解。它的本质是从原问题的一组解出发改进到另一组较好的 解,再从这组改进的解出发进一步改进。在搜索过程中,它利用结构和随机的信息,是满足目标的决策 获得最大的生存可能,是一种概率型算法。
遗传算法主要借用生物中“适者生存”的原则,在遗传算法中,染色体对应的是数据或数组,通常由 一维的串结构数据来表示。串上的各个位置对应一个基因座,而各个位置上所取的值对等位基因。遗传 算法处理的是基因型个体,一定数量的个体组成了群体。群体的规模就是个体的数目。不同个体对环境 的适应度不同,适应度打的个体被选择进行遗传操作产生新个体。本文转载自http://www.biyezuopin.vip/onews.asp?id=16719每次选择两个染色体进行产生一组新 染色体,染色体也可能发生变异,得到下一代群体。
1.2遗传算法基本要素
1.参数编码:可以采用位串编码、实数编码、多参数级联编码等
2.设定初始群体:
1.启发 / 非启发给定一组解作为初始群体
2.确定初始群体的规模
3.设定适应度函数:将目标函数映射为适应度函数,可以进行尺度变换来保证非负、归一等特性
4.设定遗传操作:
1.选择:从当前群体选出一系列优良个体,让他们产生后代个体
2.交叉:两个个体的基因进行交叉重组来获得新个体
3.变异:随机变动个体串基因座上的某些基因
5.设定控制参数:例如变异概率、交叉程度、迭代上限等。

import numpy as np
import random
import matplotlib.pyplot as plt
import copy
import timefrom matplotlib.ticker import MultipleLocator
from scipy.interpolate import interpolateCITY_NUM = 20
City_Map = 100 * np.random.rand(CITY_NUM, 2)DNA_SIZE = CITY_NUM     #编码长度
POP_SIZE = 100          #种群大小
CROSS_RATE = 0.6        #交叉率
MUTA_RATE = 0.2         #变异率
Iterations = 1000       #迭代次数# 根据DNA的路线计算距离
def distance(DNA):dis = 0temp = City_Map[DNA[0]]for i in DNA[1:]:dis = dis + ((City_Map[i][0]-temp[0])**2+(City_Map[i][1]-temp[1])**2)**0.5temp = City_Map[i]return dis+((temp[0]-City_Map[DNA[0]][0])**2+(temp[1]-City_Map[DNA[0]][1])**2)**0.5# 计算种群适应度,这里适应度用距离的倒数表示
def getfitness(pop):temp = []for i in range(len(pop)):temp.append(1/(distance(pop[i])))return temp-np.min(temp) + 0.000001# 选择:根据适应度选择,以赌轮盘的形式,适应度越大的个体被选中的概率越大
def select(pop, fitness):s = fitness.sum()temp = np.random.choice(np.arange(len(pop)), size=POP_SIZE, replace=True,p=(fitness/s))p = []for i in temp:p.append(pop[i])return p# 4.2 选择:锦标赛选择法
def selectII(pop, fitness):p = []for i in range(POP_SIZE):temp1 = np.random.randint(POP_SIZE)temp2 = np.random.randint(POP_SIZE)DNA1 = pop[temp1]DNA2 = pop[temp2]if fitness[temp1] > fitness[temp2]:p.append(DNA1)else:p.append(DNA2)return p# 变异:选择两个位置互换其中的城市编号
def mutation(DNA, MUTA_RATE):if np.random.rand() < MUTA_RATE: # 以MUTA_RATE的概率进行变异# 随机产生两个实数,代表要变异基因的位置,确保两个位置不同,将2个所选位置进行互换mutate_point1 = np.random.randint(0, DNA_SIZE)mutate_point2 = np.random.randint(0,DNA_SIZE)while(mutate_point1 == mutate_point2):mutate_point2 = np.random.randint(0,DNA_SIZE)DNA[mutate_point1],DNA[mutate_point2] = DNA[mutate_point2],DNA[mutate_point1]# 4.1 变异:在父代中随机选择两个点,然后反转之间的部分
def mutationII(DNA, MUTA_RATE):if np.random.rand() < MUTA_RATE:mutate_point1 = np.random.randint(0, DNA_SIZE)mutate_point2 = np.random.randint(0, DNA_SIZE)while (mutate_point1 == mutate_point2):mutate_point2 = np.random.randint(0, DNA_SIZE)if(mutate_point1 > mutate_point2):mutate_point1, mutate_point2 = mutate_point2, mutate_point1DNA[mutate_point1:mutate_point2].reverse()# 4.1 变异:调用 I 和 II
def mutationIII(DNA, MUTA_RATE):mutationII(DNA, MUTA_RATE)mutation(DNA, MUTA_RATE)# 交叉变异
# muta = 1时变异调用 mutation;
# muta = 2时变异调用 mutationII;
# muta = 3时变异调用 mutationIII
def crossmuta(pop, CROSS_RATE, muta=1):new_pop = []for i in range(len(pop)):   # 遍历种群中的每一个个体,将该个体作为父代n = np.random.rand()if n >= CROSS_RATE:     # 大于交叉概率时不发生变异,该子代直接进入下一代temp = pop[i].copy()new_pop.append(temp)# 小于交叉概率时发生变异if n < CROSS_RATE:# 选取种群中另一个个体进行交叉list1 = pop[i].copy()list2 = pop[np.random.randint(POP_SIZE)].copy()status = True# 产生2个不相等的节点,中间部分作为交叉段,采用部分匹配交叉while status:k1 = random.randint(0, len(list1) - 1)k2 = random.randint(0, len(list2) - 1)if k1 < k2:status = Falsek11 = k1# 两个DNA中待交叉的片段fragment1 = list1[k1: k2]fragment2 = list2[k1: k2]# 交换片段后的DNAlist1[k1: k2] = fragment2list2[k1: k2] = fragment1# left1就是 list1除去交叉片段后剩下的DNA片段del list1[k1: k2]left1 = list1offspring1 = []for pos in left1:# 如果 left1 中有与待插入的新片段相同的城市编号if pos in fragment2:# 找出这个相同的城市编号在在原DNA同位置编号的位置的城市编号# 循环查找,直至这个城市编号不再待插入的片段中pos = fragment1[fragment2.index(pos)]while pos in fragment2:pos = fragment1[fragment2.index(pos)]# 修改原DNA片段中该位置的城市编号为这个新城市编号offspring1.append(pos)continueoffspring1.append(pos)for i in range(0, len(fragment2)):offspring1.insert(k11, fragment2[i])k11 += 1temp = offspring1.copy()# 根据 type 的值选择一种变异策略if muta == 1:mutation(temp, MUTA_RATE)elif muta == 2:mutationII(temp, MUTA_RATE)elif muta == 3:mutationIII(temp, MUTA_RATE)# 把部分匹配交叉后形成的合法个体加入到下一代种群new_pop.append(temp)return new_popdef print_info(pop):fitness = getfitness(pop)maxfitness = np.argmax(fitness)     # 得到种群中最大适应度个体的索引print("最优的基因型:", pop[maxfitness])print("最短距离:",distance(pop[maxfitness]))# 按最优结果顺序把地图上的点加入到best_map列表中best_map = []for i in pop[maxfitness]:best_map.append(City_Map[i])best_map.append(City_Map[pop[maxfitness][0]])X = np.array((best_map))[:,0]Y = np.array((best_map))[:,1]# 绘制地图以及路线plt.figure()plt.rcParams['font.sans-serif'] = ['SimHei']plt.scatter(X,Y)for dot in range(len(X)-1):plt.annotate(pop[maxfitness][dot],xy=(X[dot],Y[dot]),xytext = (X[dot],Y[dot]))plt.annotate('start',xy=(X[0],Y[0]),xytext = (X[0]+1,Y[0]))plt.plot(X,Y)# 3.2 种群规模对算法结果的影响
def pop_size_test():global POP_SIZEITE = 3 # 每个值测试多次求平均数以降低随机误差i_list = [10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]b_list = []t_list = []for i in i_list:print(i)POP_SIZE = itime_cost = 0min_path = 0for j in range(ITE):time_start = time.time()ans = tsp_solve()min_path += min(ans)time_end = time.time()time_cost += time_end - time_startb_list.append(min_path / ITE)t_list.append(time_cost / ITE)show_test_result(i_list, b_list, t_list, "POP_SIZE")# 3.3 交叉概率对算法结果的影响
def cross_rate_test():global CROSS_RATEITE = 3 # 每个值测试多次求平均数以降低随机误差i_list = range(0, 21)b_list = []t_list = []ii_list = [] # [0, 0.05, 0.1, ... 0.95, 1]for i in i_list:print(i)CROSS_RATE = 0.05 * iii_list.append(CROSS_RATE)time_cost = 0min_path = 0for j in range(ITE):time_start = time.time()ans = tsp_solve()min_path += min(ans)time_end = time.time()time_cost += time_end - time_startb_list.append(min_path / ITE)t_list.append(time_cost / ITE)show_test_result(ii_list, b_list, t_list, "CROSS_RATE")# 3.4 变异概率对算法结果的影响
def muta_rate_test():global MUTA_RATEITE = 3 # 每个值测试多次求平均数以降低随机误差i_list = range(0, 21)b_list = []t_list = []ii_list = [] # [0, 0.05, 0.1, ... 0.95, 1]for i in i_list:print(i)MUTA_RATE = 0.05 * iii_list.append(MUTA_RATE)time_cost = 0min_path = 0for j in range(ITE):time_start = time.time()ans = tsp_solve()min_path += min(ans)time_end = time.time()time_cost += time_end - time_startb_list.append(min_path / ITE)t_list.append(time_cost / ITE)show_test_result(ii_list, b_list, t_list, "MUTA_RATE")# 3.5 交叉概率和变异概率对算法结果的影响
def cross_muta_test():s = np.array([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])X, Y = np.meshgrid(s,s)Z = np.zeros(shape=(11, 11))global MUTA_RATEglobal CROSS_RATEfor i in range(11):for j in range(11):print(str(i) + ":" + str(j))CROSS_RATE = X[0,i]MUTA_RATE = Y[0,j]ans = tsp_solve()Z[i, j] = min(ans)ax = plt.axes(projection='3d')ax.plot_surface(X, Y, Z, rstride=1, cstride=1,cmap='rainbow', edgecolor='none')ax.set_xlabel("CROSS_RATE")ax.set_ylabel("MUTA_RATE")ax.set_zlabel("Shortest_Path")ax.set_title('TSP')plt.show()# 3.2-3.4 生成参数测试结果的可视化图表
def show_test_result(i_list, b_list, t_list, msg):ax1 = plt.subplot(121)ax1.plot(i_list, b_list, 'b')ax1.set_xlabel(msg)ax1.set_ylabel("Shortest Path")ax2 = plt.subplot(122)ax2.plot(i_list, t_list, 'r')ax2.set_xlabel(msg)ax2.set_ylabel("Cost Time")plt.show()# 求解TSP问题并返回最大值
# muta 指定变异方式,sel 指定选择方式
def tsp_solve(muta=1, sel=1):pop = []li = list(range(DNA_SIZE))for i in range(POP_SIZE):random.shuffle(li)l = li.copy()pop.append(l)best_dis = []# 进行选择,交叉,变异,并把每代的最优个体保存在best_dis中for i in range(Iterations):  # 迭代N代pop = crossmuta(pop, CROSS_RATE, muta=muta)fitness = getfitness(pop)maxfitness = np.argmax(fitness)best_dis.append(distance(pop[maxfitness]))if sel == 1:pop = select(pop, fitness)  # 选择生成新的种群elif sel == 2:pop = selectII(pop, fitness)  # 选择生成新的种群return best_dis# 4.1 块逆转变异策略对比测试
def opt1_test():ITE = 20    # 测试次数i_list = range(ITE)b_list = []     # 每次求出的最短路径t_list = []     # 每次求解的耗时b_listII = []t_listII = []b_listIII = []t_listIII = []for i in i_list:print(i)# I. 原两点互换异策略time_start = time.time()b_list.append(min(tsp_solve(muta=1)))time_end = time.time()t_list.append(time_end - time_start)# II. 块逆转变异策略time_startII = time.time()b_listII.append(min(tsp_solve(muta=2)))time_endII = time.time()t_listII.append(time_endII - time_startII)# III. 同时使用上述两种编译策略time_startIII = time.time()b_listIII.append(min(tsp_solve(muta=3)))time_endIII = time.time()t_listIII.append(time_endIII - time_startIII)# 做排序处理,方便比较b_list.sort()t_list.sort()b_listII.sort()t_listII.sort()b_listIII.sort()t_listIII.sort()ax1 = plt.subplot(121)ax1.plot(i_list, b_list, 'b', label="Origin")ax1.plot(i_list, b_listII, 'r', label="Block-reversal")ax1.plot(i_list, b_listIII, 'g', label="Origin + Block-reversal")ax1.set_ylabel("Shortest Path")ax2 = plt.subplot(122)ax2.plot(i_list, t_list, 'b', label="Origin")ax2.plot(i_list, t_listII, 'r', label="Block-reversal")ax2.plot(i_list, t_listIII, 'g', label="Origin + Block-reversal")ax2.set_ylabel("Cost Time")plt.legend()plt.show()# 4.2 锦标赛选择策略对比测试
def opt2_test():ITE = 20  # 测试次数i_list = range(ITE)b_list = []  # 每次求出的最短路径t_list = []  # 每次求解的耗时b_listII = []t_listII = []b_listIII = []t_listIII = []for i in i_list:print(i)# I. 原赌轮盘选择策略time_start = time.time()b_list.append(min(tsp_solve(sel=1)))time_end = time.time()t_list.append(time_end - time_start)# II. 锦标赛选择策略time_startII = time.time()b_listII.append(min(tsp_solve(sel=2)))time_endII = time.time()t_listII.append(time_endII - time_startII)# III. 锦标赛选择策略 + 两点互换变异 + 块逆转变异策略time_startIII = time.time()b_listIII.append(min(tsp_solve(sel=2,muta=3)))time_endIII = time.time()t_listIII.append(time_endIII - time_startIII)# 做排序处理,方便比较b_list.sort()t_list.sort()b_listII.sort()t_listII.sort()b_listIII.sort()t_listIII.sort()ax1 = plt.subplot(121)ax1.plot(i_list, b_list, 'b', label="Origin")ax1.plot(i_list, b_listII, 'r', label="Tournament")ax1.plot(i_list, b_listIII, 'g', label="Tournament + Block-reversal + Origin")ax1.set_ylabel("Shortest Path")ax2 = plt.subplot(122)ax2.plot(i_list, t_list, 'b', label="Origin")ax2.plot(i_list, t_listII, 'r', label="Tournament")ax2.plot(i_list, t_listIII, 'g', label="Tournament + Block-reversal + Origin")ax2.set_ylabel("Cost Time")plt.legend()plt.show()# 3.1 原程序的主函数 - 求解不同规模的TSP问题的算法性能
def ori_main():time_start = time.time()pop = [] # 生成初代种群popli = list(range(DNA_SIZE))for i in range(POP_SIZE):random.shuffle(li)l = li.copy()pop.append(l)best_dis= []# 进行选择,交叉,变异,并把每代的最优个体保存在best_dis中for i in range(Iterations):  # 迭代N代pop = crossmuta(pop, CROSS_RATE)fitness = getfitness(pop)maxfitness = np.argmax(fitness)best_dis.append(distance(pop[maxfitness]))pop = select(pop, fitness)  # 选择生成新的种群time_end = time.time()print_info(pop)print('逐代的最小距离:',best_dis)print('Totally cost is', time_end - time_start, "s")plt.figure()plt.plot(range(Iterations),best_dis)# 4.1 块逆转变异策略运行效果展示
def opt1_main():time_start = time.time()pop = []    # 生成初代种群popli = list(range(DNA_SIZE))for i in range(POP_SIZE):random.shuffle(li)l = li.copy()pop.append(l)best_dis= []# 进行选择,交叉,变异,并把每代的最优个体保存在best_dis中for i in range(Iterations):  # 迭代N代pop = crossmuta(pop, CROSS_RATE, muta=3)fitness = getfitness(pop)maxfitness = np.argmax(fitness)best_dis.append(distance(pop[maxfitness]))pop = select(pop, fitness)  # 选择生成新的种群time_end = time.time()print_info(pop)print('逐代的最小距离:',best_dis)print('Totally cost is', time_end - time_start, "s")plt.figure()plt.plot(range(Iterations),best_dis)if __name__ == "__main__":ori_main()    # 原程序的主函数opt1_main()   # 块逆转变异策略运行效果展示plt.show()plt.close()# opt1_test()   # 块逆转变异策略对比测试# opt2_test()   # 锦标赛选择策略对比测试# pop_size_test()       # POP_SIZE 种群规模参数测试# cross_rate_test()     # CROSS_RATE 交叉率参数测试# muta_rate_test()      # MUTA_RATE 变异率参数测试# cross_muta_test()     # 交叉率和变异率双参数测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Vue3+elementplus搭建通用管理系统实例七:通用表格实现上

一、本章内容 使用配置的方式实现表格的界面的自动生成、自动解析实体配置信息,并生成表格列、筛选项等功能,完整课程地址 二、效果预览 三、开发视频

动手实现深度学习(12): 卷积层的实现

9.1 卷积层的运算 传送门: https://www.cnblogs.com/greentomlee/p/12314064.html github: Leezhen2014: https://github.com/Leezhen2014/python_deep_learning 卷积的forward 卷积的计算过程网上的资料已经做够好了,没必要自己再写一遍。只把资料搬运到这里: http://deepl…

【进击的JavaScript|高薪面试必看】JS基础-作用域和闭包

六年代码两茫茫&#xff0c;不思量&#xff0c;自难忘 6年资深前端主管一枚&#xff0c;只分享技术干货&#xff0c;项目实战经验&#xff0c;面试指导 关注博主不迷路~ 本系列文章是博主精心整理的面试热点问题&#xff0c;吸收了大量的技术博客与面试文章&#xff0c;总结多年…

Java毕设项目——网上宠物店管理系统(java+SSM+Maven+Mysql+Jsp)

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM 技术&#xff1a;Jsp JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a…

收银台——Web自动化测试

目录 一&#xff0c;收银台项目的主要功能&#xff1a; 二&#xff0c;Web自动化测试 一&#xff0c;Web自动化测试&#xff0c;设计测试用例 二&#xff0c;编写测试用例代码 三&#xff0c;测试结果&#xff1a; 四&#xff0c;总结&#xff1a; 一&#xff0c;收银台项…

JVM监控:JMX组件与底层原理

JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架 &#xff0c;从Java5.0开始引入到标准Java技术平台中。JMX是一套标准的代理和服务&#xff0c;实际上&#xff0c;用户可以在任何Java应用程序中使用这些代理和服务实现管理。 其实JMX也可以看作一个框架&a…

一建报名重大变动 部分专业考生2022年不能报名一级建造师考试?

2022年度一级建造师资格考试报名证明事项实行告知承诺制&#xff0c;应试人员须通过中国人事考试网的全国专业技术人员资格考试报名服务平台进行网上注册、报名和缴费。 云南报名时间&#xff1a;2022年9月14日—9月21日&#xff1b;缴费截止时间&#xff1a;9月14日—9月23日…

【Android】App开发-控件篇

App开发是一个工作量比较大的项目&#xff0c;要学习App开发首先我们要先去学习手机中的各类工具和信息是怎么运行的&#xff0c;我们可以使用哪些工具来对手机进行设置。这里我采用的开发工具是Android studio。 目录 Textview控件 文本框控件&#xff1a; 阴影/模糊度控件…

第12章 软件测试基础 12.1-软件测试 12.2-验证与确认 12.3-软件缺陷

目录 一、软件测试基础主要内容 二、软件测试 1、软件测试的定义 2、软件测试的对象 3、软件测试的目的 4、考点 &#xff08;1&#xff09;软件测试的目的 &#xff08;2&#xff09;软件测试的对象 三、验证与确认 1、验证&#xff08;Verification&#xff09; 2、确认&…

pycharm安装opencv-python报错

嘿嘿&#xff0c;大家好&#xff0c;我又遇到拦路的小可爱了&#xff01; 报错内容 3): Read timed out. WARNING: You are using pip version 21.3.1; however, version 22.2.2 is available. You should consider upgrading via the E:\daimabao\python\bigdata\Scripts\pyt…

【小月电子】安路国产FPGA开发板系统学习教程-LESSON7串口通信

串口通信例程讲解若要观看该博客配套的视频教程&#xff0c;可点击此链接根据多年工作经验&#xff0c;总结出的FPGA的设计流程&#xff0c;概括起来总共有以上12步&#xff0c;其中根据项目难易度可省去其中一些步骤。比如非常简单的项目&#xff0c;我们可以省去虚线框里面的…

【数据结构】二叉树的遍历

文章目录 5.3 二叉树的遍历 5.3.1 概述 5.3.2 遍历方式【重点】 5.3.3 遍历方式&#xff1a;递归实现【重点】 5.3.4 遍历方式&#xff1a;非递归实现 5.3 二叉树的遍历 5.3.1 概述 二叉树的遍历&#xff1a;沿着某条搜索路径对二叉树中的结点进行访问&#xff0c;使得每…

grpc|protobuf的安装、编译、运行笔记(C++)

一、下载grpc源码 如果你的电脑/服务器可以做代理&#xff0c;然后稳定链接上 GitHub 那么完全可以按照 GitHub 的官方文档来操作&#xff0c;我这里采用 Gitee 镜像来操作 git clone https://gitee.com/jiangxy__loey/grpc.git二、下载依赖库 进入grpc目录&#xff0c;然后…

为什么残差连接的网络结构更容易学习?

为什么残差连接的网络结构更容易学习&#xff1f; 【写在前面】 不仅仅在resnet中&#xff0c;在各种网络结构中大家都喜欢使用残差连接的设计&#xff0c;并声称这有利于网络的优化&#xff0c;这是为什么呢&#xff1f;能给出一个有说服力的答案吗&#xff1f; Why the re…

1.数据校验-拦截器-全局异常-json数据处理

目录 1.数据校验-拦截器-全局异常-json数据处理 1. JSR303 2. JSR303中含有的注解 3. spring中使用JSR303进行服务端校验 3.1 导入依赖包 3.2 添加验证规则 3.3执行校验 3.4 错误信息的展示 4. SpringMVC定义Restfull接口 5.1 增加spring配置 5.2 Controller 5.3 格…

Mstsc(远程桌面连接)命令的高级用法

Mstsc远程桌面连接,这个是微软操作系统自带的一个命令,相信很多人都用过,但是如果说这个命令还有高级用法,估计很多人都没有用过,其实这个命令还是很强大的,今天咱们就来说一下mstsc的高级用法Mstsc远程桌面连接,这个是微软操作系统自带的一个命令,相信很多人都用过,但…

20220912--CSP-S模拟4

A. 石子游戏 B. 大鱼吃小鱼 C. 黑客 D. 黑客-续A. 石子游戏 首先了解一个叫做 \(\operatorname{Nim}\) 游戏的玩意 通常的 \(\operatorname{Nim}\) 游戏的定义是这样的: 有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)” 如果轮…

自制操作系统日志——第十二天

自制操作系统日志——第十二天 从今天开始&#xff0c;我们将花费两天的时间来进行计算机中定时器的制作。有了定时器后&#xff0c;才能够为程序和cpu更加便利的进行计时。可能会稍难一些了&#xff01;&#xff01;&#xff01; 做好准备&#xff0c;冲&#xff01;&#xf…

ConcurrentLinkedQueue解析

概述 ConcurrentLinkedQueue实际对应的是LinkedList,是一个线程安全的无界队列&#xff0c;但LinkedList是一个双向链表&#xff0c;而ConcurrentLinkedQueue是单向链表。ConcurrentLinkedQueue线程安全在于设置head、tail以及next指针时都用的cas操作&#xff0c;而且node里的…

00Android studio安装

目录一.下载Android studio二.安装Android studio三.打开软件一.下载Android studio 官网&#xff1a;https://developer.android.google.cn/studio 下载&#xff1a;由于是国外的网站&#xff0c;国内下载会比较慢 二.安装Android studio 打开&#xff1a; 点击【Next】 点击…