求解旅行商问题的三种精确性建模方法,性能差距巨大
文章目录
- 旅行商问题介绍
- 三种模型对比
- 求解模型1
- 决策变量
- 目标函数
- 约束条件
- Python代码
- 求解模型2
- 决策变量
- 目标函数
- 约束条件
- Python代码
- 求解模型3
- 决策变量
- 目标函数
- 约束条件
- Python代码
- 三个模型的优势与不足
旅行商问题介绍
旅行商问题 (Traveling Salesman Problem, TSP) 是一个经典的组合优化问题,目标是找到一条最短路径,该路径必须经过每个城市一次且仅一次,最终返回到起始城市。
问题的输入:
- N N N: 城市的总数。
- c c c: 城市之间的距离, c i j c_{ij} cij 表示城市 i i i 和城市 j j j 之间的距离。
问题的输出:
三种模型对比
以下是三种模型的对比:
特性 | 模型1 | 模型2 | 模型3 |
---|---|---|---|
变量定义 | 有向弧( x i j x_{ij} xij) | 无向弧( x i j x_{ij} xij,仅 i < j i < j i<j) | 无向弧( x i j x_{ij} xij, x i j x_{ij} xij 与 x j i x_{ji} xji 意义相同) |
变量数量 | N × ( N − 1 ) N \times (N-1) N×(N−1) | N × ( N − 1 ) / 2 N \times (N-1)/2 N×(N−1)/2 | N × ( N − 1 ) N \times (N-1) N×(N−1) |
约束类型 | 显式约束 | 隐式无向性 + 惰性约束 | 显式对称约束 + 惰性约束 |
子环消除 | 静态约束 | 动态惰性约束 | 动态惰性约束 |
求解效率 | 较低 | 中等 | 较高 |
运行时间 (50个城市) | 12.0 s | 0.2 s | 0.1 s |
注意:
- 以上测试是基于gurobi 12.0。
- 模型1的求解效率是gurobi 12.0 高于 gurobi 11.0,模型2和3反之。
求解模型1
决策变量
- x i j x_{ij} xij: 二进制变量,如果旅行者从城市 i i i 访问城市 j j j,则 x i j = 1 x_{ij} = 1 xij=1,否则 x i j = 0 x_{ij} = 0 xij=0。
- u i u_i ui: 辅助变量,用于表示城市 i i i 的访问顺序(顺序编号,整数)。
目标函数
最小化总的旅行距离:
minimize Z = ∑ i = 0 N − 1 ∑ j = 0 , j ≠ i N − 1 c i j ⋅ x i j \text{minimize} \quad Z = \sum_{i=0}^{N-1}\sum_{j=0,j \neq i}^{N-1} c_{ij} \cdot x_{ij} minimizeZ=i=0∑N−1j=0,j=i∑N−1cij⋅xij
约束条件
-
每个城市有且仅有一个出度:
∑ j = 0 , j ≠ i N − 1 x i j = 1 , ∀ i = 0 , 1 , … , N − 1 \sum_{j=0, j \neq i}^{N-1} x_{ij} = 1, \quad \forall i = 0, 1, \ldots, N-1 j=0,j=i∑N−1xij=1,∀i=0,1,…,N−1 -
每个城市有且仅有一个入度:
∑ i = 0 , i ≠ j N − 1 x i j = 1 , ∀ j = 0 , 1 , … , N − 1 \sum_{i=0, i \neq j}^{N-1} x_{ij} = 1, \quad \forall j = 0, 1, \ldots, N-1 i=0,i=j∑N−1xij=1,∀j=0,1,…,N−1 -
防止子环的约束:
u i − u j + N ⋅ x i j ≤ N − 1 , ∀ i , j = 1 , … , N − 1 , i ≠ j u_i - u_j + N \cdot x_{ij} \leq N - 1, \quad \forall i, j = 1, \ldots, N-1, \; i \neq j ui−uj+N⋅xij≤N−1,∀i,j=1,…,N−1,i=j
- 注意此处 i , j i,j i,j 是从 1 1 1 开始,不是从 0 0 0 开始。这是因为,假设路径为 0 → 1 → 2 → 0 0 \rightarrow 1 \rightarrow 2 \rightarrow 0 0→1→2→0,那么 0 0 0 的路径索引即低于1又高于2,出现矛盾。(~~ 在看公式的时候没注意到此处细节,复现的时候卡在这里了一段时间 ~~)
Python代码
import time
import numpy as np
from gurobipy import *
import matplotlib.pyplot as plt
from scipy.spatial.distance import cdistdef generate_random_city_coordinates(num_cities):"""生成随机的城市坐标及距离矩阵"""np.random.seed(3) # 锁定随机种子以确保可重复性city_coordinates = np.random.rand(num_cities, 2) # 生成随机城市坐标(0到1之间的浮点数)c = cdist(city_coordinates, city_coordinates, metric='euclidean') # 计算城市之间的欧几里得距离return c,city_coordinatesdef plot_route(city_coordinates, solution):"""可视化城市和路径"""# 画出路径plt.plot(city_coordinates[solution][:, 0], city_coordinates[solution][:, 1], color='black', marker='o')plt.plot([city_coordinates[solution[0], 0], city_coordinates[solution[-1], 0]],[city_coordinates[solution[0], 1], city_coordinates[solution[-1], 1]], color='black', marker='o') # 回到起点# 去掉坐标轴黑框ax = plt.gca()ax.spines['top'].set_color('none')ax.spines['right'].set_color('none')ax.spines['left'].set_color('none')ax.spines['bottom'].set_color('none')# 隐藏坐标轴刻度ax.xaxis.set_ticks_position('none')ax.yaxis.set_ticks_position('none')# 隐藏坐标轴刻度标签ax.set_xticks([]) ax.set_yticks([])plt.show()def solve_tsp(num_cities):"""解决旅行商问题 (TSP)"""# 生成距离矩阵c,city_coordinates = generate_random_city_coordinates(num_cities)# 创建模型TSP = Model("Traveling Salesman Problem")# 定义决策变量x = TSP.addVars(num_cities, num_cities, vtype=GRB.BINARY, name='visit') # 边的访问变量u = TSP.addVars(num_cities, vtype=GRB.INTEGER, lb=0, name='aux') # 辅助变量用于限制子环# 设置目标函数:最小化总的旅行距离TSP.setObjective(quicksum(x[i, j] * c[i, j] for i in range(num_cities) for j in range(num_cities)), GRB.MINIMIZE)# 设置约束条件# 1. 每个城市有且仅有一个出度TSP.addConstrs(quicksum(x[i, j] for j in range(num_cities) if i != j) == 1 for i in range(num_cities))# 2. 每个城市有且仅有一个入度TSP.addConstrs(quicksum(x[j, i] for j in range(num_cities) if i != j) == 1 for i in range(num_cities))# 3. 防止子环的约束TSP.addConstrs(u[i] - u[j] + x[i, j] * num_cities <= num_cities - 1 for i in range(1, num_cities) for j in range(1, num_cities) if i != j)# 求解模型TSP.optimize()if TSP.status == GRB.OPTIMAL:print("找到最优解。")# 输出选定的路径route = []for i in range(num_cities):for j in range(num_cities):if x[i, j].x > 0.5: # 判断是否选择了这条边route.append((i, j))# 寻找完整路径current_city = 0solution = [current_city]while True:current_city = next((j for i,j in route if i == current_city ),None)solution.append(current_city)if current_city == 0:breakprint("最优路径为路径为:","->".join(map(str,solution)))print(f"总旅行距离: {TSP.ObjVal:.2f}")plot_route(city_coordinates, solution)return TSP# 主程序入口
if __name__ == "__main__":start_time = time.time() # 标记开始时间number_of_city_coordinates = 50 # 城市数量solve_tsp(number_of_city_coordinates) # 调用解决TSP的函数runtime = time.time() - start_time # 计算运行时间print(f"程序运行时间: {runtime:.2f}秒")
求解模型2
决策变量
- x i j x_{ij} xij: 二进制变量,如果旅行者经过城市 i i i 和城市 j j j 之间的弧,则 x i j = 1 x_{ij} = 1 xij=1,否则 x i j = 0 x_{ij} = 0 xij=0。 (注意:仅定义 i < j i < j i<j 的边,即 x i j x_{ij} xij 表示无向边。)
目标函数
最小化总的旅行距离:
minimize Z = ∑ i = 0 N − 1 ∑ j = i + 1 N − 1 c i j ⋅ x i j \text{minimize} \quad Z = \sum_{i=0}^{N-1}\sum_{j=i+1}^{N-1} c_{ij} \cdot x_{ij} minimizeZ=i=0∑N−1j=i+1∑N−1cij⋅xij
约束条件
-
每个城市有且仅有两个邻接边(入度和出度之和为2):
∑ j = 0 , j < i N − 1 x j i + ∑ j = 0 , j > i N − 1 x i j = 2 , ∀ i = 0 , 1 , … , N − 1 \sum_{j=0, j < i}^{N-1} x_{ji} + \sum_{j=0, j > i}^{N-1} x_{ij} = 2, \quad \forall i = 0, 1, \ldots, N-1 j=0,j<i∑N−1xji+j=0,j>i∑N−1xij=2,∀i=0,1,…,N−1 -
防止子环的约束(作为惰性约束,通过回调函数动态添加):
∑ i , j ∈ S x i j ≤ ∣ S ∣ − 1. \sum_{i, j \in S} x_{ij} \leq |S| - 1. i,j∈S∑xij≤∣S∣−1.
(其中 S S S 是任意子集,表示子环中的城市集合。)
Python代码
- 注意代码中的 tsp_model.update() 在Gurobi 12.0 中必须加,在 Gurobi 11.0 中可加可不加。(~~ 此处又是卡时间的一个小坑 ~~)
import time
import math
import numpy as np
import gurobipy as gp
import matplotlib.pyplot as plt
from itertools import combinations,permutations
from gurobipy import * # 使用gurobipy库
from scipy.spatial.distance import cdistdef generate_random_cities(num_cities):"""生成随机的城市坐标及距离矩阵"""np.random.seed(3) # 锁定随机种子以确保可重复性city_coordinates = np.random.rand(num_cities, 2) # 生成随机城市坐标(0到1之间的浮点数)c = cdist(city_coordinates, city_coordinates, metric='euclidean') # 计算城市之间的欧几里得距离return c,city_coordinates# 计算两个城市之间的距离
def distance(city_index1, city_index2, distance_matrix):"""计算城市 city_index1 和 city_index2 之间的距离"""return distance_matrix[city_index1, city_index2]def plot_route(city_coordinates, solution):"""可视化城市和路径"""# 画出路径plt.plot(city_coordinates[solution][:, 0], city_coordinates[solution][:, 1], color='black', marker='o')plt.plot([city_coordinates[solution[0], 0], city_coordinates[solution[-1], 0]],[city_coordinates[solution[0], 1], city_coordinates[solution[-1], 1]], color='black', marker='o') # 回到起点# 去掉坐标轴黑框ax = plt.gca()ax.spines['top'].set_color('none')ax.spines['right'].set_color('none')ax.spines['left'].set_color('none')ax.spines['bottom'].set_color('none')# 隐藏坐标轴刻度ax.xaxis.set_ticks_position('none')ax.yaxis.set_ticks_position('none')# 隐藏坐标轴刻度标签ax.set_xticks([]) ax.set_yticks([])plt.show()# 创建 Gurobi 模型
def create_model(num_cities, distance_matrix):"""创建旅行商问题的 Gurobi 模型"""model = Model("Traveling Salesman Problem")# 定义变量:只使用单向变量 (i < j)city_pairs = list(combinations(range(num_cities), 2))vars = model.addVars(city_pairs, vtype = GRB.BINARY, name='x')# 每个城市的边数为 2model.addConstrs(vars.sum(c, '*') + vars.sum('*', c) == 2 for c in range(num_cities))# 设置目标函数:最小化总的旅行距离model.setObjective(quicksum(vars[i, j] * distance_matrix[i, j] for i, j in city_pairs), GRB.MINIMIZE)model.update()return model, vars# 回调函数 - 用于消除子巡环
def subtourelim(model, where):"""回调函数,用于切断子巡环"""if where == GRB.Callback.MIPSOL:vals = model.cbGetSolution(model._vars) # 获取当前解中选择的边selected_edges = gp.tuplelist((i, j) for (i, j), val in vals.items() if val > 0.5)tour = find_shortest_subtour(selected_edges) # 寻找短子巡环if len(tour) < len(capitals):pairs_tour = [(tour[i], tour[i+1]) if tour[i] < tour[i+1] else (tour[i+1], tour[i]) for i in range(len(tour) - 1)]if tour[-1] < tour[0]:pairs_tour.append((tour[-1],tour[0]))else:pairs_tour.append((tour[0],tour[-1]))# 对于子巡环中的每对城市,添加子巡环消除约束model.cbLazy(gp.quicksum(model._vars[i, j] for i, j in pairs_tour) <= len(pairs_tour) - 1)# 寻找给定边的最短子巡环
def find_shortest_subtour(edges):unvisited = capitals[:]shortest_cycle = capitals[:] # 初始占位,后续会替换while unvisited:this_cycle = []neighbors = unvisitedwhile neighbors:current = neighbors[0]this_cycle.append(current)unvisited.remove(current)neighbors = [j for i, j in edges.select(current, '*') if j in unvisited] + [i for i, j in edges.select('*', current) if i in unvisited]if len(this_cycle) <= len(shortest_cycle):shortest_cycle = this_cycle # 更新为新的最短子巡环return shortest_cycle# 主程序
if __name__ == "__main__":start_time = time.time() # 开始时间记录number_of_cities = 50 # 城市数量capitals = list(range(number_of_cities))# 生成随机城市坐标和距离矩阵distance_matrix,city_coordinates = generate_random_cities(number_of_cities)# 创建模型并优化tsp_model, vars = create_model(number_of_cities, distance_matrix)tsp_model._vars = varstsp_model.Params.lazyConstraints = 1 # 启用懒约束tsp_model.optimize(subtourelim) # 优化模型# 检查模型状态,输出结果if tsp_model.status == GRB.OPTIMAL:print("找到最优解!")selected_edges = [(i, j) for i, j in vars.keys() if vars[i, j].x > 0.5]shortest_cycle = find_shortest_subtour(gp.tuplelist(selected_edges))total_distance = tsp_model.ObjValprint('最优路径', shortest_cycle)print('最优长度', total_distance)plot_route(city_coordinates, shortest_cycle)else:print("未找到可行解或模型求解失败。")elapsed_time = time.time() - start_time # 计算运行时间print(f"程序运行时间: {elapsed_time:.2f}秒")
求解模型3
- 该模型来自于此处:https://github.com/Gurobi/modeling-examples/blob/master/traveling_salesman/tsp.ipynb。
- 因为感觉该模型有些冗余,所以将该模型改写为模型2,然而还是原模型的求解效率高。
决策变量
- x i j x_{ij} xij: 二进制变量,如果旅行者经过城市 i i i 和城市 j j j 之间的弧,则 x i j = 1 x_{ij} = 1 xij=1,否则 x i j = 0 x_{ij} = 0 xij=0。
(注意: x i j x_{ij} xij 和 x j i x_{ji} xji 是两个独立的变量,表示相同的无向弧。)
目标函数
最小化总的旅行距离:
minimize Z = ∑ i = 0 N − 1 ∑ j = 0 , j ≠ i N − 1 c i j ⋅ x i j \text{minimize} \quad Z = \sum_{i=0}^{N-1}\sum_{j=0, j \neq i}^{N-1} c_{ij} \cdot x_{ij} minimizeZ=i=0∑N−1j=0,j=i∑N−1cij⋅xij
约束条件
-
每个城市有且仅有两个邻接边(入度和出度之和为2):
∑ j = 0 , j ≠ i N − 1 x i j + ∑ j = 0 , j ≠ i N − 1 x j i = 2 , ∀ i = 0 , 1 , … , N − 1 \sum_{j=0, j \neq i}^{N-1} x_{ij} + \sum_{j=0, j \neq i}^{N-1} x_{ji} = 2, \quad \forall i = 0, 1, \ldots, N-1 j=0,j=i∑N−1xij+j=0,j=i∑N−1xji=2,∀i=0,1,…,N−1 -
双向路径对称性约束:
x i j = x j i , ∀ i , j = 0 , 1 , … , N − 1 , i ≠ j x_{ij} = x_{ji}, \quad \forall i, j = 0, 1, \ldots, N-1, \; i \neq j xij=xji,∀i,j=0,1,…,N−1,i=j -
防止子环的约束(作为惰性约束,通过回调函数动态添加):
∑ i , j ∈ S x i j ≤ ∣ S ∣ − 1. \sum_{i, j \in S} x_{ij} \leq |S| - 1. i,j∈S∑xij≤∣S∣−1.
(其中 S S S 是任意子集,表示子环中的城市集合。)
Python代码
import time
import numpy as np
import gurobipy as gp
import matplotlib.pyplot as plt
from itertools import combinations,permutations
from gurobipy import * # 使用gurobipy库
from scipy.spatial.distance import cdistdef generate_random_cities(num_cities):"""生成随机的城市坐标及距离矩阵"""np.random.seed(3) # 锁定随机种子以确保可重复性city_coordinates = np.random.rand(num_cities, 2) # 生成随机城市坐标(0到1之间的浮点数)c = cdist(city_coordinates, city_coordinates, metric='euclidean') # 计算城市之间的欧几里得距离return c,city_coordinates# 计算两个城市之间的距离
def distance(city_index1, city_index2, distance_matrix):"""计算城市 city_index1 和 city_index2 之间的距离"""return distance_matrix[city_index1, city_index2]def plot_route(city_coordinates, solution):"""可视化城市和路径"""# 画出路径plt.plot(city_coordinates[solution][:, 0], city_coordinates[solution][:, 1], color='black', marker='o')plt.plot([city_coordinates[solution[0], 0], city_coordinates[solution[-1], 0]],[city_coordinates[solution[0], 1], city_coordinates[solution[-1], 1]], color='black', marker='o') # 回到起点# 去掉坐标轴黑框ax = plt.gca()ax.spines['top'].set_color('none')ax.spines['right'].set_color('none')ax.spines['left'].set_color('none')ax.spines['bottom'].set_color('none')# 隐藏坐标轴刻度ax.xaxis.set_ticks_position('none')ax.yaxis.set_ticks_position('none')# 隐藏坐标轴刻度标签ax.set_xticks([]) ax.set_yticks([])plt.show()# 创建 Gurobi 模型
def create_model(num_cities, distance_matrix):"""创建旅行商问题的Gurobi模型"""# 创建模型tsp_model = Model("Traveling Salesman Problem")# 单向城市对Pairings = combinations(range(num_cities), 2)# 双向城市对city_pairs = list(permutations(range(num_cities), 2))# 添加变量:城市 i 和城市 j 是否相邻vars = tsp_model.addVars(city_pairs, vtype=GRB.BINARY, name='x')# 每个城市的边数为 2tsp_model.addConstrs(vars.sum(c, '*') == 2 for c in range(num_cities))# 无向边tsp_model.addConstrs(vars[i,j]==vars[j,i] for i,j in Pairings)# 设置目标函数:最小化2倍的总旅行距离tsp_model.setObjective(quicksum(vars[i, j] * distance(i, j, distance_matrix) for i,j in city_pairs), GRB.MINIMIZE)tsp_model.update()return tsp_model, vars# 回调函数 - 用于消除子巡环
def subtourelim(model, where):"""回调函数,用于切断子巡环"""if where == GRB.Callback.MIPSOL:vals = model.cbGetSolution(model._vars) # 获取当前解中选择的边selected_edges = gp.tuplelist((i, j) for i, j in model._vars.keys() if vals[i, j] > 0.5)tour = find_shortest_subtour(selected_edges) # 寻找短子巡环if len(tour) < len(capitals):# 对于子巡环中的每对城市,添加子巡环消除约束model.cbLazy(gp.quicksum(model._vars[i, j] for i, j in combinations(tour, 2)) <= len(tour) - 1)# 寻找给定边的最短子巡环
def find_shortest_subtour(edges):unvisited = capitals[:]shortest_cycle = capitals[:] # 初始占位,后续会替换while unvisited:this_cycle = []neighbors = unvisitedwhile neighbors:current = neighbors[0]this_cycle.append(current)unvisited.remove(current)neighbors = [j for i, j in edges.select(current, '*') if j in unvisited]if len(this_cycle) <= len(shortest_cycle):shortest_cycle = this_cycle # 更新为新的最短子巡环return shortest_cycle# 主程序
if __name__ == "__main__":start_time = time.time() # 开始时间记录number_of_cities = 50 # 城市数量capitals = list(range(number_of_cities))# 生成随机城市坐标和距离矩阵distance_matrix,city_coordinates = generate_random_cities(number_of_cities)# 创建模型并优化tsp_model, vars = create_model(number_of_cities, distance_matrix)tsp_model._vars = varstsp_model.Params.lazyConstraints = 1 # 启用懒约束tsp_model.optimize(subtourelim) # 优化模型# 检查模型状态,输出结果if tsp_model.status == GRB.OPTIMAL:print("找到最优解!")selected_edges = [(i, j) for i, j in vars.keys() if vars[i, j].x > 0.5]shortest_cycle = find_shortest_subtour(gp.tuplelist(selected_edges))total_distance = tsp_model.ObjVal/2print('最优路径', shortest_cycle)print('最优长度', total_distance)plot_route(city_coordinates, shortest_cycle)else:print("未找到可行解或模型求解失败。")elapsed_time = time.time() - start_time # 计算运行时间print(f"程序运行时间: {elapsed_time:.2f}秒")
三个模型的优势与不足
模型1的优势与不足
- 优势:
- 模型简单直观,易于实现。
- 使用静态约束消除子环,适合初学者理解。
- 不足:
- 静态约束可能导致松弛解质量较差,求解效率低。
- 变量和约束数量较多。
模型2的优势与不足
- 优势:
- 变量数量较少,约束较少。
- 不足:
- 回调函数需要额外处理单向变量的双向性,效率略低。
- 隐式无向性可能导致求解器无法充分利用对称性优化。
模型3的优势与不足
- 优势:
- 显式对称约束帮助求解器更快识别问题结构,求解效率高。
- 回调函数直接处理双向变量,效率更高。
- 适合大规模问题。
- 不足:
- 模型不简洁,变量数量较多( N × ( N − 1 ) N \times (N-1) N×(N−1)),但通过显式约束弥补了效率损失。
相关文章:

求解旅行商问题的三种精确性建模方法,性能差距巨大
文章目录 旅行商问题介绍三种模型对比求解模型1决策变量目标函数约束条件Python代码 求解模型2决策变量目标函数约束条件Python代码 求解模型3决策变量目标函数约束条件Python代码 三个模型的优势与不足 旅行商问题介绍 旅行商问题 (Traveling Salesman Problem, TSP) 是一个经…...

SQL-leetcode—1193. 每月交易 I
1193. 每月交易 I 表:Transactions ---------------------- | Column Name | Type | ---------------------- | id | int | | country | varchar | | state | enum | | amount | int | | trans_date | date | ---------------------- id 是这个表的主键。 该表包含…...

【MySQL — 数据库增删改查操作】深入解析MySQL的 Retrieve 检索操作
Retrieve 检索 示例 1. 构造数据 创建表结构 create table exam1(id bigint, name varchar(20) comment同学姓名, Chinesedecimal(3,1) comment 语文成绩, Math decimal(3,1) comment 数学成绩, English decimal(3,1) comment 英语成绩 ); 插入测试数据 insert into ex…...

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(九)(完结篇)
文章目录 一、成绩查询模块实现1、学生成绩查询功能实现1.1 页面设计1.2 前端页面实现1.3 后端功能实现2、成绩分段查询功能实现2.1 页面设计2.2 前端页面实现2.3 后端功能实现二、试卷练习模块实现三、我的分数模块实现1、 页面设计2、 前端页面实现3、 后端功能实现四、交流区…...

离散 VS 流程制造,制造业的 “双生花” 如何绽放
在制造业中,我们常看到两种不同生产景象:有的企业生产一气呵成,有的则由众多环节组合。 这源于离散制造和流程制造两种常见生产模式。它们在生产管理上特点与区别明显。 下面,我们从概念、特点、企业生产管理方式,以…...

freeswtch目录下modules.conf各个模块的介绍【freeswitch版本1.6.8】
应用模块(applications) mod_abstraction: 为其他模块提供抽象层,有助于简化模块开发,让开发者能在统一框架下开发新功能,减少与底层系统的直接交互,提高代码可移植性和可维护性。 mod_av&#…...

循序渐进kubernetes-RBAC(Role-Based Access Control)
文章目录 概要Kubernetes API了解 Kubernetes 中的 RBACRoles and Role Bindings:ClusterRoles and ClusterRoleBindings检查访问权限:外部用户结论 概要 Kubernetes 是容器化应用的强大引擎,但仅仅关注部署和扩展远远不够,集群的安全同样至…...

第3章 基于三电平空间矢量的中点电位平衡策略
0 前言 在NPC型三电平逆变器的直流侧串联有两组参数规格完全一致的电解电容,由于三电平特殊的中点钳位结构,在进行SVPWM控制时,在一个完整开关周期内,直流侧电容C1、C2充放电不均匀,各自存储的总电荷不同,电容电压便不均等,存在一定的偏差。在不进行控制的情况下,系统无…...

基于SpringBoot的阳光幼儿园管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...

Python 数据分析 - Matplotlib 绘图
Python 数据分析 - Matplotlib 绘图 简介绘图折线图单线多线子图 散点图直方图条形图纵置横置多条 饼图 简介 Matplotlib 是 Python 提供的一个绘图库,通过该库我们可以很容易的绘制出折线图、直方图、散点图、饼图等丰富的统计图,安装使用 pip install…...

uniapp版本升级
1.样式 登录进到首页,弹出更新提示框,且不可以关闭,侧边返回直接退出! 有关代码: <uv-popup ref"popupUpdate" round"8" :close-on-click-overlay"false"><view style"…...

Django ORM解决Oracle表多主键的问题
现状 以Django 3.2为例 Django ORM 设计为默认使用单一主键(通常是自增的 id 字段),这一选择主要基于以下核心原因: 简化ORM设计与操作 统一访问方式外键关联简化 避免歧义冲突 主键语义明确防止隐式依赖 性能与数据库兼容 索引…...

机器学习2 (笔记)(朴素贝叶斯,集成学习,KNN和matlab运用)
朴素贝叶斯模型 贝叶斯定理: 常见类型 算法流程 优缺点 集成学习算法 基本原理 常见方法 KNN(聚类模型) 算法性质: 核心原理: 算法流程 优缺点 matlab中的运用 朴素贝叶斯模型 朴素贝叶斯模型是基于贝叶斯…...

ubuntu解决普通用户无法进入root
项目场景: 在RK3566上移植Ubuntu20.04之后普通用户无法进入管理员模式 问题描述 在普通用户使用sudo su试图进入管理员模式的时候报错 解决方案: 1.使用 cat /etc/passwd 查看所有用户.最后一行是 若无用户,则使用 sudo useradd -r -m -s /…...

Time Constant | RC、RL 和 RLC 电路中的时间常数
注:本文为 “Time Constant” 相关文章合辑。 机翻,未校。 How To Find The Time Constant in RC and RL Circuits June 8, 2024 💡 Key learnings: 关键学习点: Time Constant Definition: The time constant (τ) is define…...

数据结构测试题2
一、单选题(每题 2 分,共20分) 1. 栈和队列的共同特点是( A )。 A.只允许在端点处插入和删除元素 B.都是先进后出 C.都是先进先出 D.没有共同点 2. 用链接方式存储的队列,在进行插入运算时( C ) A. 仅修改头指针 B. 头…...

在虚拟机里运行frida-server以实现对虚拟机目标软件的监测和修改参数(一)(android Google Api 35高版本版)
frida-server下载路径 我这里选择较高版本的frida-server-16.6.6-android-x86_64 以root身份启动adb 或 直接在android studio中打开 adb root 如果使用android studio打开的话,最好选择google api的虚拟机,默认以root模式开启 跳转到下载的frida-se…...

mysql_store_result的概念和使用案例
mysql_store_result() 是 MySQL C API 中的一个函数,用于检索一个完整的结果集到一个客户端。当执行一个查询(通常是 SELECT 查询)并希望处理所有返回的数据时,可以使用此函数。 概念 mysql_store_result() 函数的原型如下&…...

Linux进程调度与等待:背后的机制与实现
个人主页:chian-ocean 文章专栏-Linux 前言: 当一个进程发起某种操作(如I/O请求、信号、锁的获取等),但该操作需要的资源暂时不可用时,进程会被操作系统挂起,进入“等待队列”或“阻塞状态”。…...

网易云音乐歌名可视化:词云生成与GitHub-Pages部署实践
引言 本文将基于前一篇爬取的网易云音乐数据, 利用Python的wordcloud、matplotlib等库, 对歌名数据进行深入的词云可视化分析. 我们将探索不同random_state对词云布局的影响, 并详细介绍如何将生成的词云图部署到GitHub Pages, 实现数据可视化的在线展示. 介绍了如何从原始数据…...
单片机基础模块学习——DS18B20温度传感器芯片
不知道该往哪走的时候,就往前走。 一、DS18B20芯片原理图 该芯片共有三个引脚,分别为 GND——接地引脚DQ——数据通信引脚VDD——正电源 数据通信用到的是1-Wier协议 优点:占用端口少,电路设计方便 同时该协议要求通过上拉电阻…...

《网络数据安全管理条例》施行,企业如何推进未成年人个人信息保护(下)
文章目录 前言三、全流程推进未成年人个人信息保护1、处理前:未成年人个人信息处理的告知同意2、处理中:加强个人信息处理流程管理3、处理后:落实个人信息保护合规审计四、大型网络平台应每年发布社会责任报告前言 《网数条例》颁布前,我国已针对未成年人个人信息保护陆续…...

书生大模型实战营3
文章目录 L0——入门岛git基础Git 是什么?Git 中的一些基本概念工作区、暂存区和 Git 仓库区文件状态分支主要功能 Git 平台介绍GitHubGitLabGitee Git 下载配置验证下载 Git配置 Git验证 Git配置 Git常用操作Git简易入门四部曲Git其他指令 闯关任务任务1: 破冰活动…...

Spring Boot 集成 WebClient 实战教程 实现同步、异步请求处理以及响应式编程、响应式流、响应式Mono
该项目介绍springboot集成WebClient 实现服务的请求操作 示例中演示了,如何配置WebClient的请求头,请求参数等相关参数,实现同步、异步请求处理以及响应式编程、响应式流、响应式Mono。 为什么使用WebClient 不用RestTemplate 在 Spring Framework 5.0 及更高版本中,Res…...

C语言深入解析 printf的底层源码实现
深入解析 printf 的底层源码实现 printf 是 C 标准库中最常用的函数之一,用于格式化输出字符串。它的底层实现复杂且高效,包含多个模块化的函数和机制。本文结合 GNU C Library(glibc)的源码,详细分析 printf 的实现原…...

go 循环处理无限极数据
数据表结构: CREATE TABLE permission (id int(11) NOT NULL AUTO_INCREMENT COMMENT 权限ID,permission_name varchar(255) DEFAULT NULL COMMENT 权限名称,permission_url varchar(255) DEFAULT NULL COMMENT 权限路由,status tinyint(1) DEFAULT NULL COMMENT 权…...

C# Dynamic关键字
一、引言:开启动态编程之门 在 C# 的编程世界里,长久以来我们习惯了静态类型语言带来的严谨与稳定。在传统的 C# 编程中,变量的类型在编译时就已经确定,这就像是给每个变量贴上了一个固定的标签,在整个代码执行过程中…...

ReactNative react-devtools 夜神模拟器连调
目录 一、安装react-devtools 二、在package.json中配置启动项 三、联动 一、安装react-devtools yarn add react-devtools5.3.1 -D 这里选择5.3.1版本,因为高版本可能与夜神模拟器无法联动,导致部分功能无法正常使用。 二、在package.json中配置启…...

【教学类-89-02】20250128新年篇02——姓名藏头对联(星火讯飞+Python,五言对联,有横批)
背景需求: 过年了,我想用幼儿的名字写对联,但是我根本不会写,于是尝试让AI来写。 1.我班的孩子的名字都是2字和3字的 2.惊喜发现,AI它很快就能生成带名字的对联 但是观察发现,如果是二个名字的对联&#…...

装机爱好者的纯净工具箱
对于每一位电脑用户来说,新电脑到手后的第一件事通常是检测硬件性能。今天为大家介绍一款开源且无广告的硬件检测工具——入梦工具箱。 主要功能 硬件信息一目了然 打开入梦工具箱,首先看到的是硬件信息概览。这里不仅包含了内存、主板、显卡、硬盘等常…...