油克小学期(六)全局最优搜索(1)旅行商问题-全局

全局最优具体求解:

 遗传算法求解过程:

全局最优框架总结:

代码实现:

旅行商问题-全局最优

```c
#include "stdio.h"
#include "string.h"
#include "malloc.h"
#include "stdlib.h"
#include "time.h"
#include "math.h"
#define _CRT_SECURE_NO_WARNINGS
#define MAXCHROMLENGTH 250	//染色体的最大长度 
#define CITYNUM 5
#define MAXSIZE 20
#define TRUE 1
#define FALSE 0
#define ArcNum (CITYNUM-1)*CITYNUM/2			//城市连接边数 
#define NEIGHBORNUM ((CITYNUM-1)-1)*(CITYNUM-1)/2  //可派生路径数 
//#include <C:\Users\DELL\Desktop\数据结构实践\3图搜索\Status.c>
typedef int STATUS;
typedef char CITYNAME[MAXSIZE];
typedef struct	//定义染色体的个体结构体 
{
	int chrom[MAXCHROMLENGTH];//染色体二进制的表达形式 
	int chromlength;//染色体的实际长度 
	double fitness;//染色体的适应度函数值
}INDIVIDUAL;//染色体的个体类型
typedef struct ARCTYPE
{
	CITYNAME v, u;				//两个城市 
	float distance;				//两个城市的距离 
}*MAPGRAPH;						//地图类型 
MAPGRAPH map;
typedef struct
{
	CITYNAME city[CITYNUM + 1];   //旅行商路径(城市序列) 
	float globaldistance;       //路的总长度 
}TRAVELPATH;

CITYNAME cities[CITYNUM] = { "A","B","C","D","E" };

float dist(MAPGRAPH map, CITYNAME u, CITYNAME v)
{
	float dis = 0;
	int i;
	for (i = 0; i < ArcNum; i++)
		if ((strcmp(map[i].u, u) == 0 && strcmp(map[i].v, v) == 0)	//正向存储 
			|| (strcmp(map[i].u, v) == 0 && strcmp(map[i].v, u) == 0))	//逆向查找 
		{
			dis = map[i].distance;
			break;
		}
	return dis;
}
void TraPathDis(MAPGRAPH map, TRAVELPATH* trapath)
{
	float dis = 0;
	int i;
	for (i = 0; i < CITYNUM; i++)
		dis += dist(map, trapath->city[i], trapath->city[i + 1]);
	trapath->globaldistance = dis;		//求得路径总长度 
}
int Index(CITYNAME city, CITYNAME cities[CITYNUM])    //通过名称找到城市的存储位置
{
	int i;
	for (i = 0; i < CITYNUM; i++)	//依次査找城市的存储位置
	{
		if (strcmp(city, cities[i]) == 0) break;//找到城市的存储位置
	}
	return i;
}
void CityName(int index, CITYNAME cities[CITYNUM], CITYNAME city)
{//通过城市的存储位置找到城市名称
	int i;
	for (i = 0; i < CITYNUM; i++)//依次査找城市的存储位置
	{
		if (i == index)	//找到城市的存储位置
		{
			strcpy(city, cities[i]);//找到城市名称
			break;
		}
	}
}
void Coding(CITYNAME cities[CITYNUM], TRAVELPATH* trapath, INDIVIDUAL* indi)//进行染色体编码
{//对旅行商路径trapath进行染色体编码
	int i, j;
	indi->chromlength = CITYNUM * CITYNUM;//染色体的实际长度,即基因数
	for (i = 0; i < indi->chromlength; i++)  indi->chrom[i] = 0;//所有基因位清零
	indi->fitness = trapath->globaldistance;//适应度的值为路径长度
	for (j = 0; j < CITYNUM; j++)//第j次访问,城市次序
	{ 
		i = Index(trapath->city[j], cities);//第i个城市
		indi->chrom[j * CITYNUM + i] = 1;//第j次访问的第i个城市
	}
}
void Decoding(CITYNAME cities[CITYNUM], TRAVELPATH* trapath, INDIVIDUAL* indi)
{//将染色体解码为旅行商路径trapath
	int i, j;
	char city[MAXSIZE];//城市名称
	for (j = 0; j < indi->chromlength; j++)//基因为0或1
	{//printf("1");
		if (indi->chrom[j] == 1)//基因为1
		{
			i = j % CITYNUM;//城市的编号
			CityName(i, cities, city); //得到城市名称
			strcpy(trapath->city[j / CITYNUM], city);//城市在路径中的位置
		}
	}
	strcpy(trapath->city[CITYNUM], trapath->city[0]);//终点城市也是起点城市 
	trapath->globaldistance = indi->fitness;//适应度函数值为旅行商路径的长度
}

//初始化路径的染色体和种群
//1.InitTrapath在给定出发城市(也是终点城市)后随机初始化一条旅行商路径 
void InitTraPath(MAPGRAPH map, CITYNAME cities[CITYNUM], CITYNAME start, TRAVELPATH* trapath)
{//给定旅行商起点城市形成随机路径
	int i, j = 0, k, n;
	CITYNAME cs[CITYNUM - 1], temp;//除出发城市外的所有城市
	for (i = 0; i < CITYNUM; i++)//所有城市
	{
		if (strcmp(cities[i], start) != 0)//除出发城市
			strcpy(cs[j++], cities[i]);//保留除出发城市外的其他城市
	}
	strcpy(trapath->city[0], start);//旅行商的出发城市
	strcpy(trapath->city[CITYNUM], start);//旅行商的终点城市
	n = rand() % (CITYNUM - 1);//0~C1TYNUM-2随机数构成循环次数 
	for (i = 0; i < n; i++)//随机循环CITYNUM-1次
	{//形成旅行商随机路径(搜索空间随机节点)
		j = rand() % (CITYNUM - 1);//随机数的下标为0~CITYNUM-2
		k = rand() % (CITYNUM - 1);//随机数的下标为0~CITYNUM-2
		if (j == k) continue;//下标相同,无须交换
		strcpy(temp, cs[j]);//下标不同交换城市
		strcpy(cs[j], cs[k]);
		strcpy(cs[k], temp);
	}
	for (i = 1; i < CITYNUM; i++)//形成旅行商随机路径(搜索空间随机节点) 
	{
		strcpy(trapath->city[i], cs[i - 1]);//放回旅行商路径中
	}
	TraPathDis(map, trapath);//旅行商路径的长度
}
//2.Initlndividual在给定出发城市后随机初始化旅行商路径的一条染色体
void InitIndvidual(MAPGRAPH map, CITYNAME cities[CITYNUM], CITYNAME start, INDIVIDUAL* indi)
{//给定出发城市,随机初始化个体
	TRAVELPATH trapath;//旅行商路径
	InitTraPath(map, cities, start, &trapath);//随机生成旅行商路径
	Coding(cities, &trapath, indi);//对旅行商路径进行染色体编码
}
//3.InitPopulation在给定出发城市和种群规模后随机初始化旅行商路径的种群
void InitPopulation(MAPGRAPH map, CITYNAME cities[CITYNUM], CITYNAME start, int popsize, INDIVIDUAL population[])
{//给定旅行商路径的种群数量,随机初始化种群
	int i = 0, j, k;
	srand((unsigned)time(NULL));//时间为随机数种子
	for (i = 0; i < popsize; i++)//初始化个体
	{
		InitIndvidual(map, cities, start, &population[i]);
		//随机初始化路径的染色体个体
		for (j = 0; j < 32767; j++)			//时间延迟,产生随机数
			for (k = 0; k < 3276; k++);
	}
}
//路径染色体适应度值的求解 
//1.Evaluatelndividual用于计算染色体的适应度函数值,即旅行商路径的长度
void EvaluateIndividual(MAPGRAPH map, CITYNAME cities[CITYNUM], INDIVIDUAL* indi)
{//对染色体个体的适应度函数值求解
	TRAVELPATH trapath;//旅行商路径
	Decoding(cities, &trapath, indi);//染色体个体解码为旅行商路径
	TraPathDis(map, &trapath);//对旅行商路径长度求解
	indi->fitness = trapath.globaldistance;//旅行商路径为染色体个体的适应度函数值
}
//2.EvaluatePopulation用于计算旅行商路径种群每个个体的适应度函数值
void EvaluatePopluation(MAPGRAPH map, CITYNAME cities[CITYNUM], int popsize, INDIVIDUAL population[])
{//对种群每个个体适应度函数值的求解
	int i;
	for (i = 0; i < popsize; i++)
		EvaluateIndividual(map, cities, &population[i]);//对每条染色体个体适应度函数值的求解
}

//路径染色体个体的有效性
STATUS Efficent(INDIVIDUAL indi)//判断路径个体的有效性
{
	STATUS flag = TRUE;
	int i, j, count;//路径染色体
	int(*temp)[CITYNUM] = indi.chrom;
	for (i = 0; i < CITYNUM; i++)//第i个城市
	{
		count = 0;//城市访问次数
		for (j = 0; j < CITYNUM; j++)//访问次序
			if (temp[j][i] == 1)  count++;
		if (count > 1 || count == 0)//一个城市没被访问或访问2次以上
		{
			flag = FALSE;
			break;
		}
	}
	if (flag == TRUE)//对每个城市都只访问一次
		for (i = 0; i < CITYNUM; i++)//第i次访问
		{
			count = 0;//访问次数
			for (j = 0; j < CITYNUM; j++)//访问城市
				if (temp[i][j] == 1)  count++;
			if (count > 1 || count == 0)//—次没被访问过或被访问2次以上的城市
			{
				flag = FALSE;
				break;
			}
		}
	return flag;
}
//遗传算子
//1.SelectOperator (选择算子)从路径种群中釆用轮盘赌选择法来选取新种群
void SelectOperator(int popsize, INDIVIDUAL population[])
{//选择算子
	int i, j;
	double p, sum;//p存放随机概率,sum存放个体适应率和累计适应率
	double* ps;//当代种群染色体个体的适应率
	INDIVIDUAL* newpopulation;//新种群
	ps = (double*)malloc(popsize * sizeof(double));//开辟新路径染色体种群对应的概率空间
	newpopulation = (INDIVIDUAL*)malloc(popsize * sizeof(INDIVIDUAL));
	for (sum = 0, i = 0; i < popsize; i++)
	{
		sum += population[i].fitness;//sum 存放种群适应值总和
	}
	for (i = 0; i < popsize; i++)
	{
		ps[i] = population[i].fitness / sum;//路径染色体个体的概率
	}
	for (sum = 0, i = 0; i < popsize; i++)  sum += 1 - ps[i]; //路径染色体个体的概率之和
	for (i = 0; i < popsize; i++) ps[i] = (1 - ps[i]) / sum;//路径染色体个体概率非新概率 
	for (i = 1; i < popsize; i++) ps[i] += ps[i - 1];//新概率构成轮盘
	for (i = 0; i < popsize; i++)
	{//for循环釆用轮盘赌选择法,选取popsize个个体
		p = rand() % 1000 / 1000.0;//得到千分位小数的随机数
		for (j = 0; ps[j] < p; j++);//转动轮盘
		newpopulation[i] = population[j];//选出一个数暂存于 newpopulation 中
	}
	for (i = 0; i < popsize; i++)
		population[i] = newpopulation[i];//更新种群population 
	free(ps);//回收数据单元
	free(newpopulation);
}
//2.CrossoverOperator (交叉算子)从路径种群中通过交叉产生新种群
void CrossoverOperator(int popsize, INDIVIDUAL population[], double pc)
{//交叉算子 
	int i, j, * index, point, temp;
	double p;
	index = (int*)malloc(popsize * sizeof(int));//形成一维数组 
	for (i = 0; i < popsize; i++) index[i] = i;//初始化数组index[],种群索引 
	for (i = 0; i < popsize; i++)//for循环实现种群内随机两两交换
	{//打乱种群顺序
		point = rand() % (popsize - i);//随机建立索引index
		temp = index[i];//交换索引
		index[i] = index[point + i];
		index[point + i] = temp;
	}
	i = 0;
	while (i < popsize - 1)
	{//随机选取个体的概率,千位数
		p = rand() % 1000 / 1000.0;
		if (p < pc)//根据概率选取第i条染色体个体
		{//单个随机点的交叉点
loop:	 	point = rand() % (population[i].chromlength - 1) + 1;//交叉点位置
			for (j = point; j < population[i].chromlength; j++)
			{//索引上相邻的两个个体
				temp = population[index[i]].chrom[j];//从交叉点后逐位依次进行交换 
				population[index[i]].chrom[j] = population[index[i + 1]].chrom[j];
				population[index[i + 1]].chrom[j] = temp;
			}
			if (!Efficent(population[index[i]]) || !Efficent(population[index[i + 1]]))
			{//交叉后形成的新个体不能表达路径 
				for (j = point; j < population[i].chromlength; j++)//恢复原有个体
				{
					temp = population[index[i]].chrom[j];//从交叉点后逐位依次进行交换
					population[index[i]].chrom[j] = population[index[i + 1]].chrom[j];
					population[index[i + 1]].chrom[j] = temp;
				}
			goto loop;
			}
		}
		i += 2;//索引相邻的两个个体
	}

}
//3.MutateOperator(变异算子)从路径种群中通过变异形成新种群 
void MutateOperator(int popsize, INDIVIDUAL population[], double pm)
{//变异算子对旅行商染色体种群population进行变异 
	int j, i, chromlength;
	i=0;
	double p;//概率变量
	INDIVIDUAL indi;//染色体个体
	while (i < popsize)//每个染色体个体
	{ 
loop:   indi = population[i];//第i个染色体个体
		for (j = CITYNUM; j < population[i].chromlength; j++)//出发城市不变
		{//每个基因位
			p = rand() % 1000 / 1000.0; //随机概率,千位数
			if (p < pm) indi.chrom[j] = (indi.chrom[j] == 0) ? 1 : 0;
			//根据变异概率进行0和1的变换
		}
		if (Efficent(indi) == FALSE) goto loop;//变异后旅行商路径无效,继续变异
		population[i] = indi;//变异后旅行商路径有效,更新路径
		i++;//下一个染色体个体
	}
}

//新一代染色体群体的生成和最优染色体个体
//1.GenerateNextPopulation在路径种群中通过遗传算子产生新种群
void GenerateNextPopulation(int popsize, INDIVIDUAL population[], double pc, double pm)
{//通过遗传算子生成下一代群体
	SelectOperator(popsize, population);//选择生成群体 population 
	CrossoverOperator(popsize, population, pc);//交换生成群体 population
	MutateOperator(popsize, population, pm);//变异生成群体 population
}
//2.GetBestlndividual从路径种群中选取最优(路径最短)的路径染色体,更新迄今为止最优的路径染色体
void GetBestIndividual(int popsize, INDIVIDUAL population[], INDIVIDUAL* bestindividual, INDIVIDUAL* currentbestindividual)
{//从路径染色体种群population中求最优个体
	int i;
	*bestindividual = population[0];//默认种群中第0个个体为最优个体
	for (i = 0; i < popsize; i++)//种群中的其他个体
		if (population[i].fitness <= bestindividual->fitness)//依次比较,找出最优个体
			*bestindividual = population[i];//更新种群中的最优个体
	//当前代最优个体best individual与迄今为止最优个体currentbestindividual进行比较
	if (bestindividual->fitness < currentbestindividual->fitness)
		*currentbestindividual = *bestindividual;//更新迄今为止最优个体
}
//遗传进化,GA遗传算法的的求解过程 
void GA(MAPGRAPH map, CITYNAME cities[CITYNUM], char* start, int popsize, double pc, double pm, int generation, INDIVIDUAL* currentbestindividual)
{//遗传进化过程
	int i;
	INDIVIDUAL * population,bestindividual, oldbestindividual;//种群、最优个体
	population = (INDIVIDUAL*)malloc(popsize * sizeof(INDIVIDUAL));//分配种群单元
	InitPopulation(map, cities, start, popsize, population);//初始化种群
	bestindividual = population[0];//默认初始种群中的最优个体 
	for (i = 1; i < popsize; i++)
		if (population[i].fitness < bestindividual.fitness)//依次比较,找出最优个体
			bestindividual = population[i];//更新初始种群中最优个体
	*currentbestindividual = bestindividual;//初始种群中的最优个体为进化过程迄中今为止最优个体
	oldbestindividual = bestindividual;//迄今为止最优个体为过往最优个体
	i = 0;//连续进化最优个体,计数不变
	while (i < generation)
	{//连续进化generation代,最优个体不变
		GenerateNextPopulation(popsize, population, pc, pm);//产生新一代种群
		EvaluatePopluation(map, cities, popsize, population);//评估新一代种群
		GetBestIndividual(popsize, population, &bestindividual, currentbestindividual);
		//获取种群中最优个体和迄今为止最优个体
		if (fabs(currentbestindividual->fitness - oldbestindividual.fitness) < 1e-5)
			i++;//连续进化的代数计数
		else
		{
			oldbestindividual = *currentbestindividual;//更新过往最优个体
			i = 0;//连续进化的代数计数归零
		}
	}
}
void priTraPath(TRAVELPATH trapath)
{
	int i;
	for (i = 0; i < CITYNUM + 1; i++)
	{
		printf("%s", trapath.city[i]);
		if (i != CITYNUM)
			printf("%s", "->");
	}
	printf("\n");
	printf("global distance=%f", trapath.globaldistance);
	printf("\n");
}
void main()
{
	double pc = 0.5;//交叉率为0.25~0.99
	double pm = 0.1;//变异率为0.001~0.1
	int popsize = 12;//种群数
	int generation = 5;//连续进化最优个体,代数不变
	int count = 10;//求解次数
	INDIVIDUAL currentbestindividual;//当前最优个体
	TRAVELPATH dectrapath;//求解旅行商路径
	CITYNAME cities[CITYNUM] = { "A","B","C","D","E" };//城市有序集合
	struct ARCTYPE map[ArcNum] = { {"A","B",3},{"A","C",2},
								{"A","D",9},{"A","E",7},
								{"B","C",7},{"B","D",2},
								{"B","E",5},{"C","D",9},
								{"C","E",2},{"D","E",3} };//城市地图
	char* start = "B";//出发城市与终点城市
	int i;
	for (i = 0; i < count; i++)//求解 generation 次
	{
		GA(map, cities, start, popsize, pc, pm, generation, &currentbestindividual);//求解
		printf("Result Path:");
		Decoding(cities, &dectrapath, &currentbestindividual);//解码为路径
		priTraPath(dectrapath);//显示路径
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北城学神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值