利用改进的遗传算法(种群隔离与个体迁移)mpi并行解决tsp问题
序
关于tsp问题的概述以及如何使用遗传算法进行求解已经在上一篇文章中说明了:遗传算法解决TSP问题.
但是,作为一种演化算法,遗传算法还存在着许多问题,比如早熟的情况,很容易在算法前期就已经收敛了,大量的个体都趋向于一致,种群多样性降低。
这种情况下,就很容易陷入局部最优解。即使扩大迭代次数、种群中的个体数量,也是无济于事的。
一、优化思想
那如何进行优化呢?一种做法就是,进行种群隔离,既然一个种群会出现趋同的情况,那么我们就搞许多个种群。
如果这些种群之间不进行通信,那么是不是可以认为他们就属于两个物种呢?
如果这样的话,那么我们采用少量的个体交换,对于这些种群,他们的物种丰富度是不是就提高了?
所以,这篇文章采用并行计算的方法,我们搞16个种群,这些种群每迭代2000次进行一次个体交换,通过这种多次的交换,来丰富物种多样性。
二、迁移策略
但是,如何在16个种群间进行物种迁移呢?这就要考虑到他们迁移的拓扑结构。
2.1 环形拓扑
环形拓扑主要就是将一个种群中的某个个体迁移到其他种群中去,具体如下:

2.2 随机拓扑
随机拓扑是任意的,即:一个种群可以向其他任意种群中传递个体。如图:

看起来就很乱,而且每一次种群间交流完全都是随机的。
三、替换策略
确定了那两个种群进行交换后,如何确定交换种群中的那两个个体呢?
3.1 最优-最差替换
最优发送:即选择种群中的最优个体给其他种群。
最差替换:接收到个体的种群,用别人给的最优的,替换自己最差的个体(适应度值最小)。
3.2 随机-随机替换
随机发送:随机发送一个个体给其他种群。
随机替换:接收到其他种群发送过来的个体后,随机选择一个自己种群的个体替换掉。
四、代码实现
串行改并行,主要分为两个步骤来进行。
第一步就是写好串行的代码;
第二步把串行的代码改成并行的。
最后可能还要稍微改下bug。
4.1 串行代码
#pragma once
// 解决TSP问题的重构算法(主要是tsp0的代码风格太丑陋了,修改成C++风格)
#include<iostream>
#include<fstream>
#include<vector>
#include<time.h>
#include<string>
using namespace std;class TSP_M {
private:int numCity; // 城市数量vector<vector<double>> cityXY; // 城市坐标vector<vector<double>> cityDis; // 城市间距离的邻接矩阵int numColony = 100; // 种群数量vector<vector<int>> colony; // 种群vector<double> individualAdaptability; // 个体适应度int maxGen = 200000; // 最大演化代数int curGen = 0; // 当前演化代数double probabilityMutation = 0.02; // 变异概率vector<int> bestIndividual; // 当前最优个体double bestAdaptability; // 当前最优个体的适应度// 用于控制是否记录结果bool isRecordResult2File = false;bool isRecordResult2Console = true;public:void hello(int myrank) {cout << "Hello from " << myrank << endl;}// 计算种群中每个个体的适应度void calculateColonyAdaptability() {// 计算每个个体的适应度for (int i = 0; i < numColony; i++) {double sum = 0;for (int j = 0; j < numCity; j++) {sum += cityDis[colony[i][j]][colony[i][(j + 1) % numCity]];}individualAdaptability[i] = sum;}}// 计算个体的适应度double calculateIndividualAdaptability(vector<int> path) {double sum = 0;for (int i = 0; i < numCity; i++) {sum += cityDis[path[i]][path[(i + 1) % numCity]];}return sum;}// 计算距离矩阵void calculateDistanceMatrix() {// 初始化距离矩阵cityDis.resize(numCity);for (int i = 0; i < numCity; i++) {cityDis[i].resize(numCity);}// 计算距离矩阵for (int i = 0; i < numCity; i++) {for (int j = 0; j < numCity; j++) {cityDis[i][j] = sqrt(pow(cityXY[i][0] - cityXY[j][0], 2) + pow(cityXY[i][1] - cityXY[j][1], 2));}}}// 初始化 = 读取数据 + 计算数据void init(string filePath) {// 读取 tsp 文件readTspFile(filePath);// 初始化距离矩阵、种群等必要数据calculateData();}// 进行迭代计算void evolution() {for (; curGen < maxGen; curGen++) { // 迭代maxGen次for (int i = 0; i < numColony; i++) { // 遍历种群中所有个体vector<int> path = colony[i]; // 用于存放变异后的路径int posC1 = rand() % numCity; // 随机生成变异点1(在path中的位置)int posC2 = rand() % numCity; // 随机生成变异点2(在path中的位置)int C1, C2; // 变异点1和变异点2对应的城市编号C1 = path[posC1]; // 获取变异点1对应的城市int j = rand() % numColony; // 用于外变异的另一个 与 i个体 不同的个体int pos_flag = 0; // 用于标记变异过的点的数量double distanceChange = 0; // 用于记录距离变化while (true){// 以 probabilityMutation (default = 0.02)的概率进行内变异if (rand() / 32768.0 < probabilityMutation) {posC2 = rand() % numCity;while (posC1 == posC2) { // 如果两个变异点相同,则重新生成posC2 = rand() % numCity;}C2 = colony[i][posC2]; // 获取变异点1对应的城市}else { // 进行外变异(交叉)j = rand() % numColony;while (i == j) { // 如果两个个体相同,则重新生成j = rand() % numColony;}// 获取个体 j 中 变异点1 对应城市的位置int pos = position(colony[j], path[posC1]);C2 = colony[j][(pos + 1) % numCity]; // 获取变异点2对应的城市posC2 = position(path, C2); // 获取变异点2在个体 i 中的位置(即变异点2对应的城市在个体 i 中的位置}// 如果两个变异点相邻,continueif ((posC1 + 1) % numCity == posC2 || (posC1 - 1 + numCity) % numCity == posC2)break;//if (abs(posC1 - posC2) == 1 || abs(posC1 - posC2) == numCity - 1) {// continue;//}// 否则进行倒位操作int C1_left = path[posC1]; // 变异点1左边的城市int C1_right = path[(posC1 + 1) % numCity]; // 变异点1右边的城市int C2_left = path[posC2]; // 变异点2左边的城市int C2_right = path[(posC2 + 1) % numCity]; // 变异点2右边的城市// 计算倒位后的路径长度distanceChange += cityDis[C1_left][C2_left] + cityDis[C1_right][C2_right]- cityDis[C1_left][C1_right] - cityDis[C2_left][C2_right];invert(path, posC1, posC2); // 倒位操作pos_flag++; // 变异点数量加一if (pos_flag >= numCity)break;posC1++; // 变异点1的位置加一if (posC1 >= numCity) posC1 = 0; // 如果变异点1的位置超过了numCity,则变异点1的位置为0}// 更新子个体的适应度individualAdaptability[numColony + i] = individualAdaptability[i] + distanceChange;distanceChange = 0;// 记录 产生的 子个体for (int j = 0; j < numCity; j++) {colony[numColony + i][j] = path[j];}}// 一轮迭代之后进行选择selection();bestIndividual = colony[0]; // 更新最优个体bestAdaptability = individualAdaptability[0]; // 更新最优个体的适应度for (int i = 1; i < numColony; i++) {if (individualAdaptability[i] < bestAdaptability) {bestIndividual = colony[i];bestAdaptability = individualAdaptability[i];}}if (isRecordResult2Console) {// cout << "第" << curGen << "代的最优个体适应度为:" << bestAdaptability << endl;cout << curGen << ":" << bestAdaptability << endl;}// 每 2000 代将最优个体的适应度写入文件if (isRecordResult2File && (curGen + 1) % 2000 == 0) {// 创建 outfile.txt 文件ofstream outfile("outfile.txt", ios::app);outfile << curGen << ":" << bestAdaptability << endl;// 关闭文件outfile.close();}}}// 获取城市在路径中的位置int position(vector<int>& path, int city) {for (int i = 0; i < numCity; i++) {if (path[i] == city) {return i;}}return -1;}void invert(vector<int>& path, int pos1, int pos2) {// 如果pos1在pos2的左边,为一段if (pos1 < pos2) {for (int i = pos1 + 1, j = pos2; i < j; i++, j--) {swap(path[i], path[j]);}}// 如果pos1在pos2的右边,为两段else {// 右边的段 <= 左边的段if (numCity - 1 - pos1 <= pos2 + 1) {int i, j;for (i = pos2 + 1, j = pos1; i <= numCity - 1; i++, j--) {swap(path[i], path[j]);}for (i = 0; i < j; i++, j--) {swap(path[i], path[j]);}}// 右边的段 > 左边的段else {int i, j;for (i = pos2 + 1, j = pos1; j >= 0; i++, j--) {swap(path[i], path[j]);}for (j = numCity - 1; i < j; i++, j--) {swap(path[i], path[j]);}}}}// 在父代和子代中进行一个锦标赛选择void selection() {for (int i = 0; i < numColony; i++) {if (individualAdaptability[i] > individualAdaptability[numColony + i]) {individualAdaptability[i] = individualAdaptability[numColony + i];for (int j = 0; j < numCity; j++) {colony[i][j] = colony[numColony + i][j];}}}}// 读取tsp文件bool readTspFile(string filePath) {fstream input(filePath, ios::in);if (!input) {cout << "文件打开失败" << endl;return false;}input >> numCity; // 城市数量cout << numCity << endl;// 初始化cityXYcityXY = vector<vector<double>>(numCity, vector<double>(2));// 读取城市坐标double x, y;for (int i = 0; i < numCity; i++) {int tmp;input >> tmp >> x >> y;cout << tmp << " " << x << " " << y << endl;cityXY[i][0] = x;cityXY[i][1] = y;}// 关闭文件input.close();return true;}// 根据tsp数据计算城市之间的距离、并随机初始化种群、同时计算适应度void calculateData() {// 初始化cityDiscalculateDistanceMatrix();// 初始化colony (包括父代和子代)colony = vector<vector<int>>(2 * numColony, vector<int>(numCity));// 以时间为种子,随机生成种群srand((unsigned)time(NULL));// 建立一个用于随机生成种群的数组vector<int> tmp(numCity);for (int i = 0; i < numCity; i++) {tmp[i] = i;}// 随机初始化种群for (int i = 0; i < numColony; i++) {int numNeedToRand = numCity; // 当前需要随机的次数for (int j = 0; j < numCity; j++) {int randIndex = rand() % numNeedToRand; // 随机生成下标colony[i][j] = tmp[randIndex]; // 将随机生成的下标对应的值赋给种群swap(tmp[randIndex], tmp[numNeedToRand - 1]); // 将已经随机过的下标与最后一个下标交换numNeedToRand--; // 需要随机的次数减一}}// 初始化individualAdaptabilityindividualAdaptability = vector<double>(2 * numColony); // 后面的numColony个是用于存放子个体的适应度的// 计算种群中每个个体的适应度calculateColonyAdaptability();}// 替换掉当前种群中最差的个体void replaceWorstIndividual(vector<int> individual) {int worstIndex = 0;for (int i = 1; i < numColony; i++) {if (individualAdaptability[i] > individualAdaptability[worstIndex]) {worstIndex = i;}}individualAdaptability[worstIndex] = calculateIndividualAdaptability(individual);for (int i = 0; i < numCity; i++) {colony[worstIndex][i] = individual[i];}}// 随机替换掉当前种群中的一个个体void replaceRandomIndividual(vector<int> individual) {int randIndex = rand() % numColony;individualAdaptability[randIndex] = calculateIndividualAdaptability(individual);for (int i = 0; i < numCity; i++) {colony[randIndex][i] = individual[i];}}// get 方法// 获取城市数量int getNumCity() {return numCity;}// 获取城市坐标vector<vector<double>> getCityXY() {return cityXY;}// 获取最优个体vector<int> getBestIndividual() {int bestIndex = 0;for (int i = 1; i < numColony; i++) {if (individualAdaptability[i] < individualAdaptability[bestIndex]) {bestIndex = i;}}return colony[bestIndex];}// 随机获取一个个体vector<int> getRandomIndividual() {int randIndex = rand() % numColony;return colony[randIndex];}// 获取最大迭代次数int getMaxGen() {return maxGen;}// 获取当前迭代次数int getCurGen() {return curGen;}// set 方法void setNumCity(int numCity) {this->numCity = numCity;}void setCityXY(vector<vector<double>> cityXY) {this->cityXY = cityXY;}void setMaxGen(int maxGeneration) {this->maxGen = maxGeneration;}
};
4.2 并行代码
利用mpi编写的并行代码如下:
#include <stdio.h>
#include <mpi.h>
#include <iostream>
#include <algorithm>
#include "TSP_M.h"
using namespace std;int main(int argc, char* argv[]){// 迁移间隔int migrationInterval = 2000;// 迁移次数int migrationTimes = 100;// tsp文件路径string tspFilePath = "./pcb442.tsp";// 当前进程的编号、进程数量int myrank, numProcess;MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &myrank);MPI_Comm_size(MPI_COMM_WORLD, &numProcess);// 创建TSP_M对象TSP_M tsp;if (myrank == 0) { // 地主进程// 读取文件tsp.readTspFile(tspFilePath);// 给其他进程发送 tsp 中的数据for (int i = 1; i < numProcess; i++) {// 发送城市数量int numCity = tsp.getNumCity();MPI_Send(&numCity, 1, MPI_INT, i, 0, MPI_COMM_WORLD);// 发送城市坐标vector<vector<double>> cityXY = tsp.getCityXY();for (int j = 0; j < numCity; j++) {MPI_Send(&cityXY[j][0], 2, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);}}// 计算距离矩阵(后边计算适应度的时候会用到)tsp.calculateDistanceMatrix();}else {// 接收地主进程发送的数据// 接收城市数量int numCity;MPI_Recv(&numCity, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);// 接收城市坐标vector<vector<double>> cityXY(numCity, vector<double>(2));for (int j = 0; j < numCity; j++) {MPI_Recv(&cityXY[j][0], 2, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);}// 给TSP_M对象赋值tsp.setNumCity(numCity);tsp.setCityXY(cityXY);// 计算距离矩阵等数据tsp.calculateData();// 设置最大迭代次数为2000tsp.setMaxGen(migrationInterval);// 进行迭代计算,每2000代通信一次,进行100轮for (int i = 0; i < migrationTimes; i++) {// 进行2000代迭代tsp.evolution();// 发送当前最优个体vector<int> sendIndividualTo0 = tsp.getBestIndividual();// 随机选择一个个体// vector<int> sendIndividualTo0 = tsp.getRandomIndividual();// 向 0 号进程发送当前最优个体MPI_Send(&sendIndividualTo0[0], numCity, MPI_INT, 0, 0, MPI_COMM_WORLD);// 接收 0 号进程发送的最优个体vector<int> recvIndividualFrom0(numCity);MPI_Recv(&recvIndividualFrom0[0], numCity, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);// 替换掉当前最差个体tsp.replaceWorstIndividual(recvIndividualFrom0);// 随机替换一个个体// tsp.replaceRandomIndividual(recvIndividualFrom0);// 设置最大迭代次数 + 2000tsp.setMaxGen(tsp.getMaxGen() + migrationInterval);}}if (myrank == 0) {// 用于接收其他进程发送的个体vector<vector<int>> recvIndividuals(numProcess - 1, vector<int>(tsp.getNumCity()));// 进行100轮分发for (int i = 0; i < migrationTimes; i++) {for (int j = 1; j < numProcess; j++) {MPI_Recv(&recvIndividuals[j - 1][0], tsp.getNumCity(), MPI_INT, j, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);}// 环形拓扑,将收到的个体按顺序传递给下一个进程// 1 -> 2 -> 3 -> ... -> numProcess - 1 -> 1//for (int j = 1; j < numProcess - 1; j++) {// MPI_Send(&recvIndividuals[j - 1][0], tsp.getNumCity(), MPI_INT, j + 1, 0, MPI_COMM_WORLD);//}//MPI_Send(&recvIndividuals[numProcess - 2][0], tsp.getNumCity(), MPI_INT, 1, 0, MPI_COMM_WORLD);// 随机拓扑,将收到的个体打乱顺序vector<int> randomOrder(numProcess - 1);for (int j = 0; j < numProcess - 1; j++) {randomOrder[j] = j;}// 采用随机洗牌算法打乱顺序random_shuffle(randomOrder.begin(), randomOrder.end());// 将打乱顺序后的个体传递给农民进程for (int j = 0; j < numProcess - 1; j++) {MPI_Send(&recvIndividuals[randomOrder[j]][0], tsp.getNumCity(), MPI_INT, j + 1, 0, MPI_COMM_WORLD);}}// 输出 recvIndividuals 中的最优个体double bestFitness = tsp.calculateIndividualAdaptability(recvIndividuals[0]);int bestIndividualIndex = 0;for (int i = 1; i < numProcess - 1; i++) {double fitness = tsp.calculateIndividualAdaptability(recvIndividuals[i]);if (fitness < bestFitness) {bestFitness = fitness;bestIndividualIndex = i;}}cout << "best fitness: " << bestFitness << endl;//cout << "best individual: ";// for (int i = 0; i < tsp.getNumCity(); i++) {// cout << bestIndividuals[bestIndividualIndex][i] << " ";// }// 将最优个体写入文件fstream outfile;outfile.open("bestIndividual.txt", ios::out);for (int i = 0; i < tsp.getNumCity(); i++) {outfile << recvIndividuals[bestIndividualIndex][i] << " ";}outfile.close();}MPI_Finalize();return 0;
}
五、结果分析与讨论
采用matlab对求解结果进行可视化,代码如下:
clear all; %清除所有变量
close all; %清图
clc; %清屏C=load('./file/tsp442.txt');
R_best=load('./file/data/并行-随机拓扑-随机替换.txt');
n = size(C,1);for i=1:n-1 % 绘制历代最优路线的图plot([ C(R_best(i) + 1,1), C(R_best(i+1) + 1,1)],... % 绘制 n-1 条边[C(R_best(i) + 1,2), C(R_best(i+1) + 1,2)],'bo-');hold on;
end
plot([C(R_best(n) + 1,1), C(R_best(1) + 1,1)],... % 连接首尾边[C(R_best(n) + 1,2), C(R_best(1) + 1,2)],'ro-'); % 串行 51509.1% 并行(100轮、2000次、环形拓扑、最好-最差) 51617.3
% 并行(100轮、2000次、环形拓扑、随机-随机) 51897.5
% 并行(100轮、2000次、随机拓扑、最好-最差) 51677.7
% 并行(100轮、2000次、随机拓扑、随机-随机) 51451title(['并行(随机拓扑、最优-最差)遗传算法优化最短距离:',num2str(51677.7)]);
5.1 串行求解结果
最优路线长度:51509.1

5.2 并行求解结果
| 种群交流方式 | ||
|---|---|---|
| 拓扑结构 | 环形拓扑 | 随机拓扑 |
| 替换策略 | 最优-最差 | 随机-随机 |
拓扑结构有2种选择,替换策略也有2种选择,因此,一共有4种组合方式。
5.2.1 环形拓扑、最优-最差
最优路线长度:51617.3

5.2.2 环形拓扑、随机-随机
最优路线长度:51897.5

5.2.3 随机拓扑、最优-最差
最优路线长度:51677.7

5.2.4 随机拓扑、随机-随机
最优路线长度:51451

5.3 结果分析
上述结果是在迭代200000次得到的结果,其中每2000次进行一次种群交流。
由于计算资源有限,没有进行大量实验,但由于迭代次数较大,实验结果应当是较为稳定的。
从有限的实验结果中可以看到,随机拓扑+随机替换策略,找到的解为51451,是更优的。
这也说明,我们通过种群间交流,主要目的就是增加种群的物种多样性,而通过两种随机的策略(随机拓扑+随机替换)相互结合,相比于(环形拓扑+最优替换)增大了种群交流的随机性,较好地利用了多个种群,所以产生了较好地效果。
相关文章:
利用改进的遗传算法(种群隔离与个体迁移)mpi并行解决tsp问题
序 关于tsp问题的概述以及如何使用遗传算法进行求解已经在上一篇文章中说明了:遗传算法解决TSP问题. 但是,作为一种演化算法,遗传算法还存在着许多问题,比如早熟的情况,很容易在算法前期就已经收敛了,大量…...
【C++】—— C++11之线程库
前言: 在本期,我将给大家介绍的是 C11 中新引进的知识,即关于线程库的相关知识。 目录 (一)线程库的介绍 1、线程库的由来 2、线程库的简单介绍 (二)线程函数参数 (三…...
前端面试:【性能优化】前端缓存、CDN、懒加载和预加载
亲爱的前端开发者,Web性能对用户体验至关重要。如果你想让你的网站更快、更具吸引力,就需要关注前端性能优化。在这篇文章中,我们将深入探讨四个关键的性能优化策略:前端缓存、CDN(内容分发网络)、懒加载和…...
民族传统文化分享系统uniapp 微信小程序
管理员、用户可通过Android系统手机打开系统,注册登录后可进行管理员后端;首页、个人中心、用户管理、知识分类管理、知识资源管理、用户分享管理、意见反馈、系统管理,用户前端;首页、知识资源、用户分享、我的等。 本系统的使用…...
netty(二):NIO——处理可写事件
处理可写事件 什么情况下需要注册可写事件? 在服务端一次性无法把数据发送完的情况下,需要注册可写事件 服务端一次性是否能够把数据全部发送完成取决于服务端的缓冲区大小,该缓冲区不受程序控制 注册可写事件的步骤 判断ByteBuffer是否仍…...
PHP基本语法解析与应用指南
PHP(Hypertext Preprocessor)是一种广泛应用的开源脚本语言,特别适用于Web开发。本文将深入探讨PHP的基本语法,包括变量、数据类型、运算符、控制流等方面的内容。我们将详细介绍每个主题的基本概念、语法规则和常见应用ÿ…...
ICS PA1
ICS PA1 init.shmake 编译加速ISA计算机是个状态机程序是个状态机准备第一个客户程序parse_argsinit_randinit_loginit_meminit_isa load_img剩余的初始化工作运行第一个客户程序调试:零断点TUI 基础设施单步执行打印寄存器状态扫描内存 表达式求值词法分析递归求值…...
Java学数据结构(4)——散列表Hash table 散列函数 哈希冲突
目录 引出散列表Hash table关键字Key和散列函数(hash function)散列函数解决collision哈希冲突(碰撞)分离链接法(separate chaining)探测散列表(probing hash table)双散列(double hashing) Java标准库中的散列表总结 引出 1.散列表,key&…...
OVRL-V2: A simple state-of-art baseline for IMAGENAV and OBJECTNAV 论文阅读
论文信息 题目:OVRL-V2: A simple state-of-art baseline for IMAGENAV and OBJECTNAV 作者:Karmesh Yadav, Arjun Majumdar, Ram Ramrakhya 来源:arxiv 时间:2023 代码地址: https://github.com/ykarmesh…...
【安全】原型链污染 - Hackit2018
目录 准备工作 解题 代码审计 Payload 准备工作 将这道题所需依赖模块都安装好后 运行一下,然后可以试着访问一下,报错是因为里面没内容而已,不影响,准备工作就做好了 解题 代码审计 const express require(express) var hbs require…...
net.ipv4.ip_forward=0导致docker容器无法与外部通信
在启动一个docker容器时报错: WARNING: IPv4 forwarding is disabled. Networking will not work. 并且,此时本机上的其他容器的网络服务,只能在本机上访问,其他机器上访问不到。 原因: sysctl net.ipv4.ip_forward …...
软考高级系统架构设计师系列论文九十八:论软件开发平台的选择与应用
软考高级系统架构设计师系列论文九十八:论软件开发平台的选择与应用 一、相关知识点二、摘要三、正文四、总结一、相关知识点 软考高级系统架构设计师系列之:面向构件的软件设计,构件平台与典型架构二、摘要 本文讨论选择新软件开发平台用于重新开发银行中间业务系统。银行中…...
Springboot整合WebFlux
一、使用WebFlux入门 WebFlux整合MysqlWebFlux整合ESWebFlus整合MongdbWebFlus整合Redis 1、添加依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId><version>2.2.1.…...
uniapp 实现地图距离计算
在uniapp中实现地图距离计算可以借助第三方地图服务API来实现。以下是一种基本的实现方式: 注册地图服务API账号:你可以选择使用高德地图、百度地图等提供地图服务的厂商,注册一个开发者账号并获取API密钥。 安装相关插件或SDK:根…...
破除“中台化”误区,两大新原则考核中后台
近年来,“中台化”已成为许多企业追求的目标,旨在通过打通前后台数据和业务流程,提升运营效率和创新能力。然而,在实施过程中,一些误解可能导致“中台化”未能如预期般发挥作用。本文将探讨这些误解,并提出…...
基于YOLOV8模型和Kitti数据集的人工智能驾驶目标检测系统(PyTorch+Pyside6+YOLOv8模型)
摘要:基于YOLOV8模型和Kitti数据集的人工智能驾驶目标检测系统可用于日常生活中检测与定位车辆、汽车等目标,利用深度学习算法可实现图片、视频、摄像头等方式的目标检测,另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用…...
基于Android的课程教学互动系统 微信小程序uniapp
教学互动是学校针对学生必不可少的一个部分。在学校发展的整个过程中,教学互动担负着最重要的角色。为满足如今日益复杂的管理需求,各类教学互动程序也在不断改进。本课题所设计的springboot基于Android的教学互动系统,使用SpringBoot框架&am…...
OpenCV基础知识(9)— 视频处理(读取并显示摄像头视频、播放视频文件、保存视频文件等)
前言:Hello大家好,我是小哥谈。OpenCV不仅能够处理图像,还能够处理视频。视频是由大量的图像构成的,这些图像是以固定的时间间隔从视频中获取的。这样,就能够使用图像处理的方法对这些图像进行处理,进而达到…...
PostgreSQL命令行工具psql常用命令
1. 概述 通常情况下操作数据库使用图形化客户端工具,在实际工作中,生产环境是不允许直接连接数据库主机,只能在跳板机上登录到Linux服务器才能连接数据库服务器,此时就需要使用到命令行工具。psql是PostgreSQL中的一个命令行交互…...
【CSS 画个梯形】
使用clip-path: polygon画梯形 clip-path: polygon使用方式如下: 效果实现 clip-path: polygon 是CSS的属性之一,用于裁剪元素的形状。它可以通过定义一个具有多边形顶点坐标的值来创建一个多边形的裁剪区域,从而实现元素的非矩形裁剪效果。…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
如何做好一份技术文档?从规划到实践的完整指南
如何做好一份技术文档?从规划到实践的完整指南 🌟 嗨,我是IRpickstars! 🌌 总有一行代码,能点亮万千星辰。 🔍 在技术的宇宙中,我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…...
react更新页面数据,操作页面,双向数据绑定
// 路由不是组件的直接跳转use client,useEffect,useRouter,需3个结合, use client表示客户端 use client; import { Button,Card, Space,Tag,Table,message,Input } from antd; import { useEffect,useState } from react; impor…...
篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...
