遗传算法求解TSP问题的总结

人工智能导论——遗传算法求解TSP问题实验 一、实验目的: 熟悉和掌握遗传算法的原理、流程和编码策略,并利用遗传算法求解组合优化问题,理解求解TSP问题的流程并测试主要参数对结果的影响。 二、实验原理: 旅行商问题,即TSP问题(Traveling Salesman Problem)是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路经的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。TSP问题是一个组合优化问题。该问题可以被证明具有NPC计算复 阅读详情

本文属于个人学习总结,如有不足之处,请各位大牛指出,谢谢。

其中涉及的代码,个人均按照了一定的工程编码规范编码,使其具有可读性。在编码过程中参考了部分论文,由于记不清楚论文名称和作者了,不能一一列出,抱歉。

一、遗传算法:Genetic Algorithm

优化求解问题的一种方法,模拟生物进化过程,所以称遗传算法。

遗传算法的内容:
1)、编码
2)、适应度函数
3)、遗传进化

      1.编码

遗传算法不能直接处理问题空间的参数,必须把它们转换成遗传空间的由基因按一定结构组成的染色体或个体。这一转换操作就叫做编码,也可以称作(问题的)表示。
评估编码策略常采用以下3个规范:
a)完备性(completeness):问题空间中的所有点(候选解)都能作为GA空间中的点(染色体)表现。
b)健全性(soundness): GA空间中的染色体能对应所有问题空间中的候选解。
c)非冗余性(nonredundancy):染色体和候选解一一对应。
目前的几种常用的编码技术有二进制编码,字符编码,变成编码等。
而二进制编码是目前遗传算法中最常用的编码方法。即是由二进制{0,1}产生通常的0,1字符串来表示问题空间的候选解。它具有以下特点:
a)简单易行
b)符合最小字符集编码原则
c)便于用模式定理进行分析,因为模式定理就是以基础的
2.适应度函数
进化论中的适应度,是表示某一个体对环境的适应能力,也表示该个体繁殖后代的能力。遗传算法的适应度函数也叫评价函数,是用来判断群体中的个体的优劣程度的指标,它是根据所求问题的目标函数来进行评估的。
遗传算法在搜索进化过程中一般不需要其他外部信息,仅用评估函数来评估个体或解的优劣,并作为以后遗传操作的依据。由于遗传算法中,适应度函数要比较排序并在此基础上计算选择概率,所以适应度函数的值要取正值。由此可见,在不少场合,将目标函数映射成求最大值形式且函数值,非负的适应度函数是必要的。
      3.遗传进化
首先确定个体,种群的概念。
个体:每一个基因编码,就是一个单独的个体,没有个个体拥有各自的适应度。
种群:由多个个体构成,遗传进化都操作在种群上。
遗传进化的过程:
选择过程,交叉过程,变异过程。
选择运算:将选择算子作用于群体。选择的目的是把优化的个体直接遗传到下一代或通过配对交叉产生新的个体再遗传到下一代。选择操作是建立在群体中个体的适应度评估基础上的。
交叉运算:将交叉算子作用于群体。遗传算法中起核心作用的就是交叉算子。
变异运算:将变异算子作用于群体。即是对群体中的个体串的某些基因座上的基因值作变动。

二、TSP问题

旅行商问题,即TSP问题(Travelling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
TSP问题是一个组合优化问题。该问题可以被证明具有NP计算复杂性。因此,任何能使该问题的求解得以简化的方法,都将受到高度的评价和关注。

三、遗传算法求解TSP问题

编码: 采用最直观简单的,也是在tsp问题中最常用的直接编码,用整型数字代表城市,不重复出现且全部出现一次整型数字构成的串代表个体基因。
适应度函数: 由于一条基因序列是所有城市构成的环状,而评定tsp问题的关键是所得的环绕距离,所以适应度函数单纯取总距离的倒数,满足距离越小,适应度越大。
个体: 每一条所有城市构成的基因编码便是个体,每一个个体有其适应度。
种群: 在问题初始化时,为了让个体尽可能多的取得可能情况,选择了随机生成初始种群,即随机产生多个个体。
(以上涉及参数):种群初始数量(PopSize),城市数量(CityNumber)
源代码:
city.h
#ifndef CITY_H
#define CITY_H
struct City
{
	int x, y, number;
};
#endif //CITY_H
Individual.h
#ifndef INDIVIDUAL_H
#define INDIVIDUAL_H
#include "global.h"
class Individual
{
public:
	Individual();

	void initIndividual();

	void computeFitness();
	bool isContainCity(const int&);
	int geneLocation(const int&) const;
	void localSearch();
	bool operator < (const Individual&);
friend class GA;
private:
	int sequence[CityNumber];
	double fitness;
};
#endif //INDIVIDUAL_H

以上说明: 城市采用笛卡尔坐标系坐标描述,城市间距离直接采用欧几里得距离。
个体的私有变量描述了个体的性质,个体类对GA(遗传进化类)友元开放,方便GA操作。 其public函数设计可通过函数名明白。( 其中大部分为了交叉变异而设计)

选择算子:用于选择出个体,进行下一代繁衍,选择出的个体作为双亲,进行基因交叉。 选择的标准在于所有个体都有可能被选择,但适应度高的个体有更大的几率被选择,故采用轮盘赌的选择方法。选择出来的个体放入交叉池,进行进化操作。
交叉算子: 用于个体的交叉过程,交叉池内的个体,依照概率进行两两交叉,每次交叉产生两个个体,关于基因交叉的方式,采用了PMX的交叉方式和OX的交叉方式。
交叉算子:http://blog.youkuaiyun.com/u012750702/article/details/54563515
变异算子: 每次交叉产生的个体,都依照概率进行变异,以产生跳板增大问题的优化范围。这里变异算子采用了随机点互换方法。
      淘汰方式: 自然界存在淘汰机制,我们模拟这种机制,通过淘汰,维持了种群的规模,并且使优秀个体的基因得以保留。这里引入精英的概念。 精英是种群中最优秀的个体,精英的数量(Elite)是一个进化过程中的重要参数,在淘汰过程中,精英一定会保留下来,而其余的个体,依照其适应度进行轮盘赌选择保留。

GA.h
#ifndef GA_H
#define GA_H
#include "global.h"
#include "individual.h"
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
class GA
{
public:
	void initGA();
	void printResult(ofstream& fout);
	void printResult();
	void evolve();
private:
	Individual pop[PopSize * 3];

	void Search(Individual* offspring, const int& offspringNum);
	void PMX(const Individual& parent1, const Individual& parent2, Individual& child1, Individual& child2);
	void OX(const Individual &parent1, const Individual &parent2, Individual &child1, Individual &child2);
	void crossover(int& currentSize, const int* parentNum, Individual* offspring);
	void mutation(Individual* offspring, int& offspringNum);
	void rouletteSelection(int*, const int&, const int& num);
	void selection(Individual* offspring, const int offspringNum); 
};
#endif //GA_H
涉及参数: 交叉概率(corssPM),变异概率(variationPM),精英数量(Elite)
完整的全局变量:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
const int PopSize = 100;
const int CityNumber = 130;
const int MaxGen = 500;
const int LocalSearchTimes = 300;
const int Elite = 5;
const double variationPM = 0.1;
const double crossPM = 0.8;
extern double Distance[CityNumber][CityNumber];
void initCityDist();
#endif // GLOBAL_H
main函数:(在InitCityDist函数中从文件读取了城市信息)
main.cpp
#include "city.h"
#include "GA.h"
#include "individual.h"
#include "global.h"
#include <cstdlib>
#include <ctime>
#include <fstream>
using namespace std;
int main()
{
	ofstream fout("1.txt");
	srand((unsigned)time(NULL));
	initCityDist();
	GA ga;
	ga.initGA();
	ga.evolve();
	ga.printResult(fout);
	return 0;
} 

通过以上步骤,遗传算法求解TSP问题的基本步骤完成,但存在一个问题,即通过遗传算法不一定能够找到精确的解。遗传算法本身决定了结果不可能精确,只能逼近,为了提高准确性,避免盲目的寻找最高峰,我们通过个体的局部搜索提高准确性。
局部搜索:在每次产生一个新个体之后,对个体进行局部搜索,即在个体的基因邻域内,实现局部搜索,如果发现更优化的个体,则取而代之。这样做的意义在于,每一次进化过程中的交叉,相当于产生了新的基因,使群体的适应度更离散,而对所有个体进行一次局部搜索,则提高了整体的适应水平,能够更优的找到相对优化的解。
邻域:在此选择了基因的一段随机序列reverse,代表其邻域。 形象化就是基因序列所对应的城市环,对随机一段子序列进行解扣子操作。
局部搜索代码在以上的LocalSearch中。

至此,遗传算法求解TSP问题算是告一段落,但是遗传算法仍有很大很多还需要优化的地方,个人代码不够精良,如有建议请指出,不胜感激!

以下放出所有cpp代码:
city.cpp
#include "city.h"
#include "global.h"
#include <cmath>
#include <cstring>
#include <iostream>
#include <fstream>
using namespace std;
double Distance[CityNumber][CityNumber];

void initCityDist()
{

    double x,y,number;
	ifstream cin("input.txt");
    City citysInformation[CityNumber];
    for(int i = 0; i < CityNumber; ++i)
    {
        cin >> number >> x >> y;
        citysInformation[i].x = x;
        citysInformation[i].y = y;
        citysInformation[i].number = number;
    }
    memset(Distance, 0, sizeof(Distance));
    for(int i = 0; i < CityNumber; ++i)
        for(int j = i+1; j < CityNumber; ++j)
        {
           Distance[i][j] = Distance[j][i] =sqrt((citysInformation[i].x - citysInformation[j].x)*(citysInformation[i].x - citysInformation[j].x) + (citysInformation[i].y - citysInformation[j].y)*(citysInformation[i].y - citysInformation[j].y) );
        }
}

Individual.cpp
#include "individual.h"
#include "global.h"
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

Individual::Individual() : fitness(0) {}

void Individual::initIndividual()
{
	for (int i = 0; i < CityNumber; ++i)
		sequence[i] = i;
	random_shuffle(sequence, sequence + CityNumber);
	computeFitness();
}
void Individual::computeFitness()
{
    double sumDis = 0;
    for(int i = 0; i < CityNumber-1; ++i)
    {
        sumDis += Distance[sequence[i]][sequence[i+1]];
    }
    sumDis += Distance[sequence[CityNumber-1]][sequence[0]];
    if(sumDis)
        fitness = 1.0 / sumDis;
}
bool Individual::isContainCity(const int& city)
{
    for(int i = 0; i < CityNumber; ++i)
    {
        if(sequence[i] == city)
            return true;
    }
	return false;
}
int Individual::geneLocation(const int &gene) const
{
	for (int i = 0; i < CityNumber; ++i)
	{
		if (sequence[i] == gene)
			return i;
	}
	cout << "error" << endl;
	return 0;
}
void Individual::localSearch()
{
	//int code[CityNumber];
	Individual afterReverse;
	//memcpy(code, sequence, CityNumber*sizeof(int));
	
	for (int i = 0; i < LocalSearchTimes; ++i)
	{
		memcpy(afterReverse.sequence, sequence, CityNumber*sizeof(int));
		
		int point1 = rand() % CityNumber;
		int point2 = rand() % CityNumber;
		
		if (point1 > point2)
			swap(point1, point2);

		reverse_copy(sequence + point1, sequence + point2 + 1, afterReverse.sequence + point1);
		afterReverse.computeFitness();

		if (afterReverse.fitness > fitness)
		{
			memcpy(sequence, afterReverse.sequence, CityNumber*sizeof(int));
			computeFitness();
		}	
	}
}
bool Individual::operator < (const Individual& cmp)
{
    return fitness > cmp.fitness;
}


GA.cpp
#include "GA.h"
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <fstream>
using namespace std;

void GA::initGA() 
{
	for (int i = 0; i < PopSize; i++)
		pop[i].initIndividual();
}
void GA::printResult(ofstream& fout)
{
    fout << "Distance is:" << 1.0 / pop[0].fitness << endl;
	fout << "The route is:" << endl;
	for (int i = 0; i < CityNumber; ++i)
		fout << pop[0].sequence[i] + 1 << "->";
	
	for (int i = 0; i < PopSize; ++i)
	{
		fout << i << ":" << endl;
		for (int j = 0; j < CityNumber; ++j)
			fout << pop[i].sequence[j] + 1 << " ";
		fout << endl;
	}	
}
void GA::printResult()
{
	cout << "Distance is:" << 1.0 / pop[0].fitness << endl;
	cout << "The route is:" << endl;
	for (int i = 0; i < CityNumber; ++i)
		cout << pop[0].sequence[i] + 1 << "->";

	for (int i = 0; i < PopSize; ++i)
	{
		cout << i << ":" << endl;
		for (int j = 0; j < CityNumber; ++j)
			cout << pop[i].sequence[j] + 1 << " ";
		cout << endl;
	}
}
void GA::rouletteSelection(int* selectedNum, const int& size, const int& num)
{
    double P[3 * PopSize];
    double sumfitness = 0;
    for(int i =0; i < size; i++)
        sumfitness += pop[i].fitness;
    P[0] = pop[0].fitness / sumfitness;
    for(int i = 1; i < size - 1; ++i)
    {
            P[i] = pop[i].fitness / sumfitness + P[i-1];
    }
    P[size - 1] = 1.0;
    for (int j = 0; j < num; ++j)
    {
        double random = rand() % 10000 / 10000.00;
		for (int i = 0; i < size; ++i)
        {
            if(random <= P[i])
            {
                selectedNum[j] = i;
                break;
            }
        }
    }
}
void GA::crossover(int& offspringNum, const int* parentsNum, Individual* offspring)
{
	for (int i = 0; i < PopSize - 2; i += 2)
	{
		if (rand() % 100 / 100.0 < crossPM)
		{
			Individual parent1 = pop[parentsNum[i]];
			Individual parent2 = pop[parentsNum[i + 1]];
			Individual child1, child2;

			PMX(parent1, parent2, child1, child2);
			//OX(parent1, parent2, child1, child2);

			child1.computeFitness();
			child2.computeFitness();
			offspring[offspringNum++] = child1;
			offspring[offspringNum++] = child2;
		}
	}
}
void GA::evolve()
{
    for (int times = 0; times < MaxGen; ++times)
    {
        int offspringNum = 0;
		Individual offspring[PopSize * 3];
        int parentsNum[PopSize];

		rouletteSelection(parentsNum, PopSize, PopSize);
		crossover(offspringNum, parentsNum, offspring);
		mutation(offspring, offspringNum);

		Search(offspring, offspringNum);

		selection(offspring, offspringNum);	

    }
}
void GA::mutation(Individual* offspring, int& offspringNum)
{
	int initial = offspringNum;
	for (int i = 0; i < initial; ++i)
	{
		if (rand() % 100 / 100.0 < variationPM)
		{
			int swapCityId1 = rand() % CityNumber;
			int swapCityId2 = rand() % CityNumber;
			Individual child = offspring[i];

			swap(child.sequence[swapCityId1], child.sequence[swapCityId2]);
			child.computeFitness();
			offspring[offspringNum++] = child;
		}
	}
}
void GA::selection(Individual* offspring, const int offspringNum)
{	
	memcpy(offspring + offspringNum, pop, PopSize*sizeof(Individual));
	partial_sort(offspring, offspring + Elite, offspring + PopSize + offspringNum);

	int selectedNum[PopSize - Elite];
	rouletteSelection(selectedNum, PopSize + offspringNum, PopSize - Elite);

	for (int i = 0; i < Elite; ++i)
		pop[i] = offspring[i];
	for (int i = Elite, j = 0; i < PopSize; ++i, ++j)
		pop[i] = offspring[selectedNum[j]];
}
void GA::Search(Individual* offspring, const int& offspringNum)
{
	for (int i = 0; i < offspringNum; ++i)
	{
		offspring[i].localSearch();
	}
}
void GA::PMX(const Individual & parent1, const Individual & parent2, Individual & child1, Individual & child2)
{
	memset(child1.sequence, -1, sizeof(child1.sequence));
	memset(child2.sequence, -1, sizeof(child2.sequence));
	int point1 = rand() % CityNumber;
	int point2 = rand() % CityNumber;
	if (point1 > point2)
		swap(point1, point2);

	for (int i = point1; i < point2; ++i)
	{
		child1.sequence[i] = parent2.sequence[i];
		child2.sequence[i] = parent1.sequence[i];
	}

	for (int i = 0; i < CityNumber; ++i)
	{
		if (i >= point1 && i < point2)
			continue;
	
		int matching = parent1.sequence[i];
		while (child1.isContainCity(matching))
			matching = parent1.sequence[parent2.geneLocation(matching)];		
		child1.sequence[i] = matching;
		
		matching = parent2.sequence[i];
		while (child2.isContainCity(matching))
			matching = parent2.sequence[parent1.geneLocation(matching)];
		child2.sequence[i] = matching;
	}
}
void GA::OX(const Individual& parent1, const Individual& parent2, Individual& child1, Individual& child2)
{
	memset(child1.sequence, -1, sizeof(child1.sequence));
	memset(child2.sequence, -1, sizeof(child2.sequence));
	int point1 = rand() % CityNumber;
	int point2 = rand() % CityNumber;
	if (point1 > point2)
		swap(point1, point2);

	for (int i = point1; i < point2; ++i)
	{
		child1.sequence[i] = parent2.sequence[i];
		child2.sequence[i] = parent1.sequence[i];
	}
	int k = 0;
	int j = 0;
	for (int i = point2; i < CityNumber; ++i)
	{
		while (child1.isContainCity(parent1.sequence[k])) ++k;
		while (child2.isContainCity(parent2.sequence[j])) ++j;
		child1.sequence[i] = parent1.sequence[k++];
		child2.sequence[i] = parent2.sequence[j++];
	}
	for (int i = 0; i < point1; ++i)
	{
		while (child1.isContainCity(parent1.sequence[k])) ++k;
		while (child2.isContainCity(parent2.sequence[j])) ++j;
		child1.sequence[i] = parent1.sequence[k++];
		child2.sequence[i] = parent2.sequence[j++];
	}	
}		


遗传算法解决TSP问题 一、背景 遗传算法是基于自然选择和自然遗传机制的一种随机搜索算法,具有良好的并行性和全局寻优能力,能够自适应地调整搜索方向。这是一种相对来说比较简单的算法,因为它不需要问题求解者具备非常完备的问题领域知识,它能够通过类似生物体繁殖后代的机制自动生成问题的解,不过这个解往往不是该问题的最优解,而是相对来说的次优解。正是由于遗传算法简单的算法思路以及强大的搜索能力,它在机器人寻路、函数优化以及组合优化等诸多领域都得到了相当广泛的应用。用遗传算法求解旅行商问题就是遗传算法应用到组合优化问题中的一个经典例子。 阅读详情

相关推荐

遗传算法解决TSP旅行商问题(numpy、pandas)

遗传算法解决TSP旅行商问题(numpy、pandas)超详细

醉蕤的博客 1万+

分析遗传算法求解不同规模的tsp问题的算法性能

3. 种群规模、交叉概率和变异概率的影响:种群规模、交叉概率和变异概率是影响遗传算法性能的重要参数。综上所述,遗传算法在求解不同规模的TSP问题时,具有不同的算法性能。1. 规模较小的问题:对于规模较小的问题,遗传算法的收敛速度较快,求解时间相对较短。同时,种群中的个体数量较少,交叉和变异操作对整体种群的影响较大,有利于算法快速收敛。2. 规模较大的问题:对于规模较大的问题,遗传算法的收敛速度较慢,求解时间较长。同时,种群中的个体数量较多,交叉和变异操作对整体种群的影响较小,收敛速度受到一定限制。

2401_83491559的博客 774

遗传算法求解TSP问题(C++实现)

给定一组n个城市和俩俩之间的直达距离,寻找一条闭合的旅程,使得每个城市刚好经过一次且总的旅行距离最短。 TSP问题也称为货郎担问题,是一个古老的问题。最早可以追溯到1759年Euler提出的骑士旅行的问题。1948年,由美国兰德公司推动,TSP成为近代组合优化领域的典型难题。 TSP是一个具有广泛的应用背景和重要理论价值的组合优化问题。 近年来,有很多解决该问题的较为有效的算法不断被推出,例如Hopfield神经网络方法,模拟退火方法以及遗传算法方法等。

LeopoldZhang2000的博客 7514

遗传算法求解TSP问题

文章目录遗传算法求解TSP问题问题描述遗传算法参数编码初始群体的设定适应度函数的设计遗传操作设计交叉变异选择控制参数设定完整代码 遗传算法求解TSP问题 问题描述 使用遗传算法求下图中从北京出发经过其他四个城市之后回到北京的最短路径,两个城市之间的距离如图所示: 遗传算法 遗传算法(Genetic Algorithm, GA)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法以一种群体中的所有个体为对象,并利用随机化技术指导对一个被编码

melanchoe的博客 3772

用遗传算法求解TSP问题

原文链接: http://zh.5long.me/2015/genetic-algorithm-on-tsp/遗传算法简介关于遗传算法,首先看一段维基百科的解释: 遗传算法是模仿自然界生物进化机制发展起来的随机全局搜索和优化方法,它借鉴了达尔文的进化论和孟德尔的遗传学说。其本质是一种高效、并行、全局搜索的方法,它能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应的控制搜索过程以求得最优解。

張行之的专栏 4万+

遗传算法求解TSP问题(python版)

简介 改进和实现遗传算法,用以对旅行商问题(TSP问题)进行建模和近似求解,从而深入对启发式算法的理解。 算法流程 遗传算法解决TSP的流程是以下几部分:初始化种群、计算适应度函数、选择、交叉、变异然后不断重复直到找到理想的解。 模型设定 I 种群初始化。 需要设定的参数是随机生成的初始解的数量,该数量过少会导致种群多样性不足,数量过多会降低算法的效率,我们设定种群规模(初始解数量为150)。 II 适应度函数。 根据数据集说明,其最优解采用的边权重类型为:EDGE_WEIGHT_TYPE : EUC_2D

xieju0605的博客 1万+

遗传算法求解TSP旅行商问题

旅行商问题 旅行商问题(traveling salesman problem,TSP)可描述为:已知N个城市之间的相互距离,现有一个商人必须遍访这N个城市,并且每个城市只能访问一次,最后又必须返回出发城市。如何安排他对这些城市的访问次序,使其旅行路线总长度最短。 旅行商问题是一个典型的组合优化问题,其可能的路径数目是与城市数目N呈指数型增长的,一般很难精确地求出其最优解,因而寻找其有效的近似求解算法具有重要的理论意义,特别是当N的数目很大时,用常规的方法求解计算量太大。对庞大的搜索空间中寻求最优解,对

如何心安理得的在老板眼皮下摸鱼 1万+

C++实现遗传算法求解TSP问题详解

本文还有配套的精品资源,点击获取 简介:遗传算法是一种模拟生物进化的全局优化方法,被用来解决旅行商问题(TSP)。TSP是一种NP-hard的组合优化问题,要求找到一条最短路径访问一系列城市并返回起点。本项目使用C++编写遗传算法来近似求解TSP问题,涉及初始化种群、定义适应度函数、选择、交叉、突变等关键步骤,并提供了完整的源代码文件来指导实践。通过这个项目,可以加深对遗传...

weixin_35982453的博客 1372

基于遗传算法求解TSP问题

GA-TSP

Fine的优快云博客 1506

间充质干细胞衰老机制与抗衰老干预策略研究

干细胞技术在再生医学领域具有广阔应用前景,其中间充质干细胞(MSCs)因其多向分化潜能和免疫调节特性备受关注。细胞衰老是影响干细胞治疗效果的共性难题,表现为增殖能力下降、端粒缩短等特征。通过表观遗传学分析发现,衰老MSCs存在DNA甲基化异常和组蛋白修饰改变;线粒体功能障碍导致ATP产量锐减,ROS累积显著增加。针对这些机制,研究者开发了包括小分子化合物筛选、CRISPR基因编辑和三维培养优化在内的多种干预策略。这些技术在组织修复、抗衰老治疗等应用场景中展现出重要价值,例如可提升心肌梗死修复效率2.3倍,缩

weixin_33502772的博客 227

CANopen PDO 配置實戰:3步完成0x1800-0x1A00物件字典映射與事件觸發

本文详细解析CANopen PDO配置实战,通过3个关键步骤完成0x1800-0x1A00对象字典映射与事件触发设置。重点介绍COB-ID位域解析、映射参数配置及事件触发优化,帮助工程师实现工业自动化设备间毫秒级实时数据交换,提升系统通信效率。

weixin_33709609的博客 379

遗传算法求解TSP问题python实现

文章目录1 遗传算法总体设计2 算子设计2.1 选择算子2.2 交叉算子2.3 变异算子2.4 将种群的个体按照里程排序,并返回当前种群中的最优个体及其里程2.5 设置种群数,变异概率及其进化次数2.6 主函数3 实验结果分析4 附python源码(完整版) 1 遗传算法总体设计 Step1: 初始化参数(种群数、进化次数、变异概率,此次实验并未用到交叉概率,交叉由保留的父代随机进行); Step2: 初始种群由贪婪算法求得的个体以及其他随机生成的个体构成,评价每一个个体的适配值(路径里程决定);

行者的博客 7786

JMeter压测Dubbo接口的完整落地方案(适配3.x)

Dubbo作为主流Java微服务RPC框架,其接口压测长期面临协议私有、注册发现复杂、序列化耦合度高等技术门槛。理解Dubbo基于TCP长连接、泛化调用与SPI扩展机制的核心原理,是实现稳定压测的前提;技术价值在于绕过HTTP网关直击服务核心链路,保障大促等关键场景的性能可信度;典型应用场景包括电商订单链路压测、风控/库存等内部Dubbo服务SLA验证,以及CI/CD中性能左移实践。本文聚焦Dubbo 3.x版本,提供零第三方插件、可复用、避坑的JMeter Java Sampler落地路径。

weixin_33700809的博客 549

【建模算法】基于遗传算法求解TSP问题(matlab求解)

TSP (traveling salesman problem,旅行商问题)是典型的NP完全问题,即其最坏情况下的时间复杂度随着问题规模的增大按指数方式增长,到目前为止还未找到一个多项式时间的有效算法。本文探讨了使用matlab软件基于遗传算法求解一个TSP问题。

baidu的专栏 8007

嵌入式系统启动流程解析:ROM Code、Bootloader与启动代码的协同工作

本文深入解析嵌入式系统从通电到运行的完整启动流程,详细阐述了ROM Code、Bootloader与启动代码三者如何像接力赛般协同工作。ROM Code作为芯片固化的初始引导程序,负责硬件自检并加载Bootloader;Bootloader作为系统总指挥,初始化关键硬件并加载操作系统内核;启动代码则为C语言运行环境铺平道路。理解这三者的分工与协作,是进行系统移植和解决启动问题的关键。

dd012的博客 553

Lisflood

文献:基于SWMM和LISFLOOD-FP模型的居住区低影响开发模拟评价。问题:多个节点溢流同时,不行,待解决。目录下,cmd命令行。

警警的博客 2660
上一篇: C++ sgi STL学习笔记之non-mutating algorithm
下一篇: 766C Mahmoud and a Message[字符串][简单dp]
Qer_
博客等级 码龄11年 34粉丝 69原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值