蚁群算法求解TSP旅行商问题

问题:蚁群算法求解TSP旅行商问题
问题描述(数据来源):http://www.docin.com/p-513276781.html
数据 china.txt:

116.46 39.92
117.2 39.13
121.48 31.22
106.54 29.59
91.11 29.97
87.68 43.77
106.27 38.47
111.65 40.82
108.33 22.84
126.63 45.75
125.35 43.88
123.38 41.8
114.48 38.03
112.53 37.87
101.74 36.56
117 36.65
113.6 34.76
118.78 32.04
117.27 31.86
120.19 30.26
119.3 26.08
115.89 28.68
113 28.21
114.31 30.52
113.23 23.16
121.5 25.05
110.35 20.02
103.73 36.03
108.95 34.27
104.06 30.67
106.71 26.57
102.73 25.04
114.1 22.2
113.33 22.13
#include <bits/stdc++.h> 

using namespace std;

/*
ALPHA:信息启发因子,值越大,则蚂蚁选择之前走过的路径可能性就越大
      ,值越小,则蚁群搜索范围就会减少,容易陷入局部最优;
BETA:Beta值越大,蚁群越就容易选择局部较短路径,这时算法收敛速度会
     加快,但是随机性不高,容易得到局部的相对最优.
*/ 


#define m 100				//蚂蚁的个数
#define n 34				//城市的数量

const int NC_max = 200;		//最大迭代次数
const double Alpha = 1.0;	//表征信息素重要程度的参数
const double Beta = 5;		//表征启发式因子重要程度的参数
const double Rho = 0.1;		//信息素蒸发系数
const double Q = 100;		//信息素增加强度系数

double C[n][2];
double D[n][n];			//表示完全图的邻接矩阵
double Eta[n][n];		//表示启发式因子,为D中距离的倒数
double DeltaTau[n][n];	//表示启发式因子的变化量
double Tau[n][n];		//路径上面信息素的浓度
int Tabu[m][n];			//禁忌表,存储走过的路径

double L_best[NC_max];		//存储每次迭代的路径的最短长度
double L_ave[NC_max];		//存储每次迭代的路径的平均长度
int R_best[NC_max][n];		//存储每次迭代的最佳路线
double distance(int arr[])
{
	double sum = 0;
	int a = arr[0];
	int b;
	for(int i = 1; i < n; i++)
	{
		b = arr[i];
		sum += sqrt((C[a][0] - C[b][0]) * (C[a][0] - C[b][0]) + (C[a][1] - C[b][1]) * (C[a][1] - C[b][1]));
		a = b;
	}
	return sum;
}

void ValueInit(void)		//变量初始化函数
{
	
	ifstream fin("china.txt");
	for(int i = 0; i < 34; i++)
	{
		double x, y;
		fin >> C[i][0];
		fin >> C[i][1];
	}	
	fin.close();
	for (int i = 0; i < n; i++)			//初始化 D[n][n]
	{
		for (int j = 0; j < n; j++)
		{
			if (i != j)
				D[i][j] = pow(pow((C[i][0] - C[j][0]), 2) + pow((C[i][1] - C[j][1]), 2), 0.5);
			else
				D[i][j] = DBL_EPSILON;
		}
	}

	for (int i = 0; i < n; i++)			//初始化 Eta[n][n]
		for (int j = 0; j < n; j++)
			Eta[i][j] = 1.0 / D[i][j];

	for (int i = 0; i < n; i++)			//初始化 DeltaEta[n][n]
		for (int j = 0; j < n; j++)
			DeltaTau[i][j] = 0;

	for (int i = 0; i < n; i++)			//初始化 Tau[n][n]
		for (int j = 0; j < n; j++)
			Tau[i][j] = 1.0;

	for (int i = 0; i < m; i++)			//初始化 Tabu[m][n]
		for (int j = 0; j < n; j++)
			Tabu[i][j] = 0;
}

void ValueDisplayTabu(int (*p)[n])	//禁忌表,存储走过的路径, 显示函数
{
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cout << *(*(p + i) + j) << ' ';
		}
		cout << endl;
	}
}

void ValueDisplayTau(double(*p)[n])		//信息素的浓度,显示函数
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cout << *(*(p + i) + j) << ' ';
		}
		cout << endl;
	}
}

double rnd(double lower, double uper)	//生成lower和uper之间的一个double类型随机数
{
	return  (rand() / (double)RAND_MAX) * (uper - lower) + lower;
}

int main()
{
	//第一步:进行变量的初始化
	ValueInit();

	int NC = 0;
	while(NC < NC_max)
	{
		//第二步:将m只蚂蚁随机放到n个城市上
		vector<int> temp;
		for (int i = 0; i < ceil((double)m / (double)n); i++)
		{
			for (int j = 0; j < n; j++)
				temp.push_back(j);
		}

		random_shuffle(temp.begin(), temp.end());	//打乱temp数组中元素的次序

		for (int i = 0; i < m; i++)
		{
			Tabu[i][0] = temp[i];
		}

		//第三步:m只蚂蚁按概率函数选择n中的下一座城市,完成各自的周游
		for (int j = 1; j < n; j++)
		{
			for (int i = 0; i < m; i++)
			{
				vector<int> visited;	//第i只蚂蚁已访问过的城市
				vector<int> J;			//第i只蚂蚁待访问的城市
				vector<double> P;		//第i只蚂蚁待访问的城市的概率

				double Psum = 0.0;		//概率值和
				double rate = 0.0;		//随机数
				double choose = 0.0;	//轮盘赌算法累加值
				int to_visit;			//下一个要去的城市

				for (int k = 0; k < j; k++)
					visited.push_back(Tabu[i][k]);	//visited初始化

				for (int k = 0; k < n; k++)
				{
					if (find(visited.begin(), visited.end(), k) == visited.end())	//在visited中没有找到t
					{
						J.push_back(k);				//J初始化
						P.push_back(0.0);			//P初始化
					}
				}
				
				for (int k = 0; k < P.size(); k++)	//计算去下一座城市的概率
				{
					P[k] = pow(Tau[visited.back()][J[k]], Alpha) * pow(Eta[visited.back()][J[k]], Beta);
					Psum += P[k];
				}
				
				rate = rnd(0.0, Psum);				//使用轮盘赌算法,挑选下一座要去的城市
				for (int k = 0; k < P.size(); k++)
				{
					choose += P[k];
					if (choose > rate)
					{
						to_visit = J[k];
						break;
					}
				}
				
				
				Tabu[i][j] = to_visit;				//更新禁忌表
			}
		}

		//第四步:记录本次迭代蚂蚁行走的路线数据
		double L[m];	//记录本代每只蚂蚁走的路程,并初始化
		for (int i = 0; i < m; i++)
		{
			L[i] = 0.0;
		}
		for (int i = 0; i < m; i++)
		{
			for (int j = 0; j < n - 1; j++)
			{
				L[i] += D[Tabu[i][j]][Tabu[i][j + 1]];
			}
			L[i] += D[Tabu[i][0]][Tabu[i][n - 1]];
		}
		
		double min_value = L[0];	//声明求本代所有蚂蚁行走距离最小值的临时变量
		double sum_value = L[0];	//声明求本代所有蚂蚁行走距离总值的临时变量
		int min_index = 0;			//记录本代所有蚂蚁行走距离最小值的下标
		for (int i = 1; i < m; i++)
		{
			sum_value += L[i];
			if (L[i] < min_value)
			{
				min_value = L[i];
				min_index = i;
			}
		}

		L_best[NC] = min_value;						//每代中路径的最短长度
		L_ave[NC] = sum_value / m;					//每代中路径的平均长度

		for (int i = 0; i < n; i++)
		{
			R_best[NC][i] = Tabu[min_index][i];		//记录每代最短的路径数据
		}
		
		cout << NC << ": 代中路径的最短长度: "<< L_best[NC] << " " << ",该代中路径的平均长度:"<< L_ave[NC] << endl;	//打印各代情况 

		NC++;	//迭代继续 

		//第五步:更新信息素
		for (int i = 0; i < m; i++)
		{
			for (int j = 0; j < n - 1; j++)
			{
				DeltaTau[Tabu[i][j]][Tabu[i][j + 1]] += Q / L[i];	//此次循环在整个路径上的信息素增量
			}
			DeltaTau[Tabu[i][n - 1]][Tabu[i][0]] += Q / L[i];
		}

		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				Tau[i][j] = (1 - Rho) * Tau[i][j] + DeltaTau[i][j];	//考虑信息素挥发,更新后的信息素
			}
		}

		for (int i = 0; i < m; i++)			//禁忌表清零
			for (int j = 0; j < n; j++)
				Tabu[i][j] = 0;
	}
	
	//第六步:把结果画出来
	double min_L = L_best[0];			//所有迭代中最短距离
	int min_L_index = 0;				//所有迭代中最优路径的下标
	int Shortest_Route[n];				//所有迭代中的最优路径
	for (int i = 0; i < NC; i++)
	{
		if (L_best[i] < min_L)
		{
			min_L = L_best[i];
			min_L_index = i;
		}
	}

	cout << "最短路径长度为: " << min_L << endl;
	cout << "最优迭代次数为: " << min_L_index << endl;
	cout << "最优路径为: " << endl << "起点";

	for (int i = 0; i < n; i++)		//所有迭代中的最优路径
	{
		Shortest_Route[i] = R_best[min_L_index][i];
		cout << " -> " << Shortest_Route[i];
	}
	system("pause");
	return 0;
}

参考:https://zhuanlan.zhihu.com/p/95782157

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值