C++蚁群算法

**

C++基本蚁群算法,实现定点到任意位置的最短距离(含距离txt)

**

1.**参考博客:https://blog.csdn.net/weixin_43686942/article/details/112462825
主要在此博客上做了修改:修改了原博客BUG的产生(主要原因是内存不足和数组越界)。
**

2.关于蚁群算法的知识可参考以下资料:
链接:https://pan.baidu.com/s/1GITbyt_ygnN3mIMINHgAfQ
提取码:RBLG

3.data.txt数据如下:

**-1 10 6 8 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
10 -1 -1 -1 -1 10 20 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
6 -1 -1 8 20 10 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
8 -1 8 -1 -1 -1 10 12 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 20 -1 -1 7 -1 -1 -1 18 30 -1 -1 -1 -1 -1 -1 -1 -1
-1 10 10 -1 7 -1 -1 -1 -1 10 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 20 -1 10 -1 -1 -1 -1 -1 10 10 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 12 -1 -1 -1 -1 -1 -1 12 -1 -1 -1 25 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 7 -1 15 -1 20 -1 -1 -1 -1 -1
-1 -1 -1 -1 18 10 10 -1 7 -1 7 -1 -1 15 -1 -1 -1 -1 -1
-1 -1 -1 -1 30 -1 10 12 -1 7 -1 -1 20 -1 15 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 15 -1 -1 -1 8 -1 -1 8 16 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 20 8 -1 -1 -1 8 -1 17 -1
-1 -1 -1 -1 -1 -1 -1 -1 20 15 -1 -1 -1 -1 12 -1 8 -1 -1
-1 -1 -1 -1 -1 -1 -1 25 -1 -1 15 -1 -1 12 -1 -1 -1 10 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 8 8 -1 -1 -1 -1 -1 12
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 16 -1 8 -1 -1 -1 7 7
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 17 -1 10 -1 7 -1 11
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 12 7 11 -1 **
在这里插入图片描述

4.具体代码和运行结果如下:

运行结果:

在这里插入图片描述按下Q或q键可停止迭代

#include<iostream>
#include<string>
#include<math.h>
#include<fstream>
#include<vector>
#include<map>
#include<unordered_map>
#include<algorithm>
#include<conio.h>

using namespace std;

#pragma region 变量与常量的定义

//数据文件存放的路径
constexpr auto FILE_PATH = "D:\\data.txt";
//城市数量
const int CITY_NUMBER = 19;
//蚂蚁数量(一般为城市数量的1.5倍)
const int ANT_NUMBER = 50;
//最大迭代次数
const int  MAX_ITERATIONS_NUMBER = 150;
//路径数量
const int  PATH_NUMBER = 74;
//启发因子,信息素浓度重要性
const double ALPHA = 1.0;
//启发式重要性
const double BETA = 2.0;
//蚂蚁所携带总的信息素
const double Q = 100.0;
//信息素蒸发系数
const double ROU = 0.5;

//两两城市之间的信息素矩阵
vector<vector<double>> pheromoneMatrix;
//两两城市之间的距离
vector<vector<double>> cityDistance;
//下一代的信息素矩阵
vector<vector<double>> nextPheromoneMatrix;
//启发信息矩阵=1/cityDistance[i][j]
vector<vector<double>> inspMartix;

//关键字:string类型,值:int类型。分别对应保存每次迭代的最优路径和对应的路径距离。
map<string, int>routResult;
//含有充电设施的站点编号
vector<int>rechargeNumber = { 3,4,7,8,12,14,16 };

#pragma endregion

#pragma region 蚂蚁
class Ant {
public:
	//蚂蚁的当前位置
	int antLoc;
	//蚂蚁的禁忌表,存放已访问过的点
	int taBu[CITY_NUMBER];
	//蚂蚁走过路径的点的集合
	int antPath[PATH_NUMBER];
	//判断蚂蚁是否已经到达终点。True:表示到达,FALSE:表示未到达。
	bool flag;
};
//初始化蚁群,大小为ANT_NUMBER
Ant antColony[ANT_NUMBER];
#pragma endregion

#pragma region 城市 
class City {
public:
	//城市编号
	int cityNum;
	//选择每个点的概率
	double cityProb;
};
//初始化城市
City cityArray[CITY_NUMBER];
//线性化选择概率,用于轮盘赌算法
double lineCityProb[CITY_NUMBER];
#pragma endregion 

#pragma region 矩阵初始化功能函数
//res:表示待初始化的矩阵
//temp:表示矩阵初始化的值
void initMatrix(vector<vector<double>> &res, int temp) {
	//定义中间变量v
	vector<double>v;
	for (int i = 0; i < CITY_NUMBER; ++i) {
		//清空v
		vector<double>().swap(v);
		for (int j = 0; j < CITY_NUMBER; ++j) {
			v.push_back(temp);
		}
		res.push_back(v);
	}
}
#pragma endregion

#pragma region 返回指定范围内的随机数
///		返回指定范围内的随机浮点数
///     @param dbLow		范围起始数    
///     @param dbUpper  范围终止数
///     @return					返回的此范围内的随机数 
double randomNumber(double dbLow, double dbUpper)
{
	double dbTemp = rand() / ((double)RAND_MAX + 1.0);
	return dbLow + dbTemp * (dbUpper - dbLow);
}
#pragma endregion

#pragma region 蚁群初始化
void initAntsColony() {
	//初始化禁忌表和行走路线
	for (int i = 0; i < ANT_NUMBER; ++i) {
		for (int j = 0; j < CITY_NUMBER; ++j) {
			//初始化蚁群的禁忌表,设置每只蚂蚁的禁忌表初始化为-1,代表从未访问任何点
			antColony[i].taBu[j] = -1;
		}
		for (int j = 0; j < PATH_NUMBER; ++j) {
			//初始化蚁群的行走路径,设置每只蚂蚁的路径初始化为-1,代表还未经过任何点
			antColony[i].antPath[j] = -1;
		}
	}

	//将蚂蚁放入初始位置,此处设置每只蚂蚁的出发点为0,代表从源点出发
	for (int i = 0; i < ANT_NUMBER; ++i) {
		//设置蚂蚁的当前位置为出发位置0
		antColony[i].antLoc = 0;
		//将当前位置更新到每只蚂蚁的禁忌表中,代表已经访问过此点
		antColony[i].taBu[0] = 0;
		//将当前位置更新到每只蚂蚁的行走路径中,代表路径中已有此点
		antColony[i].antPath[0] = 0;
		//将每只蚂蚁的flag设置为0,代表每只蚂蚁都还未到达终点
		antColony[i].flag = 0;
	}
}
#pragma endregion

#pragma region 初始化城市
void initCity() {
	for (int i = 0; i < CITY_NUMBER; ++i) {
		//初始化城市结构体
		//初始化每个城市的编号为-1
		cityArray[i].cityNum = -1;
		//初始化每个城市的选择概率为0
		cityArray[i].cityProb = 0;
		//初始化线性选择概率为0
		lineCityProb[i] = 0;
	}
}
#pragma endregion

#pragma region 初始化所需的各种矩阵,并读取文件距离数据
void initVariousMatrix() {
	//初始化城市距离矩阵为-1
	initMatrix(cityDistance, -1);

	/*             数据文件的读取                */


	//创建文件流对象
	ifstream CityFile;
	//打开文件
	CityFile.open(FILE_PATH, ios::in);
	//如果文件打开失败,则退出
	if (!CityFile.is_open()) {
		cout << "Open file failure" << endl;
		exit(0);
	}
	//从文件中读取数据到城市距离矩阵之中
	for (int i = 0; i < CITY_NUMBER; ++i) {
		for (int j = 0; j < CITY_NUMBER; ++j) {
			CityFile >> cityDistance[i][j];
		}
	}
	//关闭文件
	CityFile.close();

	//初始化信息素矩阵为0
	 initMatrix(pheromoneMatrix, 0);
	//初始化下一代信息素矩阵为0
	initMatrix(nextPheromoneMatrix, 0);
	//初始化启发信息矩阵为0
	 initMatrix(inspMartix, 0);

	for (int i = 0; i < CITY_NUMBER; ++i) {
		for (int j = 0; j < CITY_NUMBER; ++j) {
			if (cityDistance[i][j] != -1) {                 //如果两个城市之间有距离
				inspMartix[i][j] = 1 / cityDistance[i][j];//启发信息为两两城市距离的倒数
				pheromoneMatrix[i][j] = 1;                //路径上信息素浓度初始值为1
			}
		}
	}
}
#pragma endregion

#pragma region 判断城市j是否在蚂蚁k的禁忌表中
bool ifCityInTabu(int k, int j) {
	for (int i = 0; i < CITY_NUMBER; ++i) {
		//如果城市j,已经在蚂蚁k的禁忌表中,则返回1
		if (j == antColony[k].taBu[i]) {
			return 1;
		}
	}
	//如果不在蚂蚁k的禁忌表中,则返回0
	return 0;
}
#pragma endregion

#pragma region 蚂蚁k从当前城市i选择下一步行进的城市j的概率
double nextCitySelProb(int k, int j) {
	//初始化选择概率公式的分子
	double p = 0;
	//初始化选择概率公式的分母
	double sum = 0;
	//i保存蚂蚁k的当前位置
	int i = antColony[k].antLoc;
	//计算P
	p = pow(pheromoneMatrix[i][j], ALPHA) * pow(inspMartix[i][j], BETA);
	//计算sum
	for (int m = 0; m < CITY_NUMBER; ++m) {
		if (cityDistance[i][j] != -1 && !ifCityInTabu(k, m)) {
			sum += pow(pheromoneMatrix[i][m], ALPHA)*pow(inspMartix[i][m], BETA);
		}
	}
	//返回从i--j的选择概率
	return (p / sum);
}
#pragma endregion

#pragma region 更新蚂蚁k的禁忌表信息
void updateAntTabu(int k, int j) {
	//蚂蚁k的当前位置赋值为j
	antColony[k].antLoc = j;
	for (int i = 0; i < CITY_NUMBER; ++i) {
		//如果蚂蚁k还未访问过j,则将蚂蚁k的禁忌表信息添加j
		if (antColony[k].taBu[i] == -1) {
			antColony[k].taBu[i] = j;
			break;
		}
	}
	//同理,将蚂蚁k的行走路径中更新一个j
	for (int i = 0; i < PATH_NUMBER; ++i) {
		if (antColony[k].antPath[i] == -1) {
			antColony[k].antPath[i] = j;
			break;
		}
	}
}
#pragma endregion

#pragma region 轮盘赌选择下一步行进的城市
//蚂蚁k,选择前进的地点j的概率
int nextCitySelect(int k, int f) {

	//记录蚂蚁可行进的城市个数,用于后面的计算
	int c = 0;

	//step 1:计算可行进的各城市的选择概率
	for (int m = 0; m < CITY_NUMBER; ++m) {
		//若城市(i,j)之间有路且j不在蚂蚁k的禁忌表中,则计算概率
		if (cityDistance[antColony[k].antLoc][m] != -1 && !ifCityInTabu(k, m)) {
			//对应的城市编号存入数组中
			cityArray[c].cityNum = m;
			//选择概率存入数组中
			cityArray[c].cityProb = nextCitySelProb(k, m);
			++c;
		}
	}

	//step 2:线性化选择概率
	for (int m = 0; m < c; ++m) {
		for (int n = m; n >= 0; n--) {
			//用于轮盘赌算法,将选择概率线性化累加
			lineCityProb[m] += cityArray[n].cityProb;
		}
	}

	//step 3 产生随机数选择城市
	//产生随机浮点数,范围0-1
	double r = randomNumber(0, 1);
	//选取的目标城市
	int j = 0;
	for (int m = 0; m < CITY_NUMBER; ++m) {
		if (r <= lineCityProb[m]) {
			//将当前选择前进的城市编号赋值给j
			j = cityArray[m].cityNum;
			//将地点j更新至蚂蚁k的禁忌表中,代表已经访问过此点
			updateAntTabu(k, j);
			if (j == f) {
				//若蚂蚁k下一步城市为目的地城市,则修改标志为1
				antColony[k].flag = 1;
			}
			//return j;
			return 0;
		}
	}
	//return f;
	return 0;

}
#pragma endregion

#pragma region 计算路径长度
int getAntLen(Ant ant) {
	//定义路径长度为0
	int len = 0;
	for (int i = 0; i < PATH_NUMBER - 1; ++i) {
		//如果蚂蚁行走的路径中有-1,表示未走过此点,则退出循环
		if (ant.antPath[i] == -1 || ant.antPath[i + 1] == -1)
			break;
		//若走过有路径,则不断累加距离结果
		else
			len += cityDistance[ant.antPath[i]][ant.antPath[i + 1]];
	}
	//返回路径长度
	return len;
}
#pragma endregion

#pragma region 计算最优路径对应的蚂蚁编号
int getBestPathAntNumber() {
	//初始化数组d为-1,保存所有蚂蚁的行走路径
	vector<int>d(ANT_NUMBER, -1);
	//假设定义蚂蚁k的路线到达目的地节点最短,即走过的路径为最短路径
	int k = 0;
	//将所有路径距离存入d中
	for (int i = 0; i < ANT_NUMBER; i++)
	{
		d.push_back(getAntLen(antColony[i]));
	}
	//定义指向最小路径的迭代器
	auto min = min_element(d.begin(), d.end());
	//计算此最短路径所对应的下标,此为蚂蚁的编号k
	k = distance(d.begin(), min);
	vector<int>(d).swap(d);
	//返回蚂蚁k
	return k;
}
#pragma endregion

#pragma region 打印最优路径所对应的蚂蚁K的路径和距离
void printBestPath(int k, int f) {
	//初始化变量res,存放路线
	string res = "";
	cout << " 最短路径为:";

	for (int i = 0; i < PATH_NUMBER - 1; ++i) {
		//如果蚂蚁k的第i条路径为-1,表示没有走过此点,退出循环
		if (antColony[k].antPath[i] == -1)
			break;
		//打印蚂蚁k的第i条路径
		cout << antColony[k].antPath[i];


		//将路径转化为字符串形式存入res中,方便打印输出
		res += to_string(antColony[k].antPath[i]);

		//若蚂蚁k的i+1条路径不为-1,代表访问过此点。即i--->i+1有路线。
		if (antColony[k].antPath[i + 1] != -1) {
			//打印"->"
			cout << "->";


			// 若此点含有充电设施
			if (find(rechargeNumber.begin(), rechargeNumber.end(), antColony[k].antPath[i + 1]) != rechargeNumber.end()) {
				res += "->(可充电站点)";
			}
			else {
				res += "->";
			}

		}

	}
	cout << endl;
	cout << " 对应距离为:" << getAntLen(antColony[k]) << endl;

	//把每次距离结果保存到map中:关键字:路线,值:对应的路径长度
	routResult[res] = getAntLen(antColony[k]);
	res.swap(res);
	//return routResult;
}
#pragma endregion

#pragma region 更新信息素矩阵
void updatePherMartix() {
	for (int i = 0; i < ANT_NUMBER; ++i) {
		//全局更新信息素矩阵
		if (antColony[i].flag == 1) {
			for (int j = 0; j < PATH_NUMBER - 1; ++j) {
				if (antColony[i].antPath[j] == -1 || antColony[i].antPath[j + 1] == -1)
					break;
				else
					nextPheromoneMatrix[antColony[i].antPath[j]][antColony[i].antPath[j + 1]]
					+= Q / getAntLen(antColony[i]);
			}
		}
	}
	//更新下一代信息素矩阵
	for (int i = 0; i < CITY_NUMBER; ++i) {
		for (int j = 0; j < CITY_NUMBER; ++j) {
			nextPheromoneMatrix[i][j] =
				(1 - ROU) * pheromoneMatrix[i][j] + nextPheromoneMatrix[i][j];
		}
	}

}
#pragma endregion

#pragma region 迭代过程
void evolution(int city) {


	cout << "开始进行迭代........." << endl;

	//初始化参数
	initAntsColony();
	initCity();
	initVariousMatrix();


	int gen = 0;
	while (gen < MAX_ITERATIONS_NUMBER) {
		int p = 0;
		while (p <11) {
			for (int i = 0; i < ANT_NUMBER; ++i) {
				if (antColony[i].flag == 1)
					continue;
				nextCitySelect(i, city);
				initCity();
			}
			++p;
		}

		

		if (gen == MAX_ITERATIONS_NUMBER - 1) {
			cout << " 迭代完成,输出结果" << endl;
			printBestPath(getBestPathAntNumber(), city);

		}
		
		
		//更新信息素矩阵
		updatePherMartix();
		//蚁群初始化
		initAntsColony();
		pheromoneMatrix = nextPheromoneMatrix;
	    initMatrix(nextPheromoneMatrix, 0);
		++gen;
	}

}
#pragma endregion

#pragma region 释放vector内存空间,避免内存无限增加而崩溃
void deleArrary() {
	vector<vector<double>>().swap(cityDistance);
	vector<vector<double>>().swap(pheromoneMatrix);
	vector<vector<double>>().swap(nextPheromoneMatrix);
	vector<vector<double>>().swap(inspMartix);
	//map<string, int>().swap(routResult);
}
#pragma endregion

#pragma region 按从小到大的顺序将vec内部value值进行排序,并打印出结果
void sortMap(map<string, int>t) {
	//routeResult存入vec中,方便将结果进行排序
	vector<pair<string, int>>vec;
	for (const auto& n : t) {
		vec.push_back(make_pair(n.first, n.second));
	}
	//将结果按照路径,从小到达进行排序
	sort(vec.begin(), vec.end(), [](const pair<string, int>& x, const pair<string, int>& y)
		-> int {
			return x.second < y.second;
		});

	//输出排序好的所有结果
	cout << "可供选择的路径中,从小到大为:" << endl;
	int i = 1;
	for (auto v : vec) {
		cout << "第" << i << "条路径为:         ";
		cout << v.first << " " << "距离为:"
			<< v.second << endl;
		++i;
	}


	cout << endl;
	cout << "建议采纳的最佳路线为:" << vec[0].first << " "
		<< "此路线距离最短,耗时最小为:"
		<< vec[0].second << endl;


	for (auto v : vec)
	{
		if (vec[0].first.find("可充电站点") != -1) {
			break;
		}
		else if (v.first.find("可充电站点") != -1) {
			cout << "若需要中途停靠充电,建议采纳的最佳路线为:"
				<< v.first
				<< "    此路线含有充电设施,总的路径为:"
				<< v.second
				<< endl;
			break;
		}
	}

	t.swap(t);
	vector<pair<string, int>>().swap(vec);
}
#pragma endregion

#pragma region 程序入口

	int main() {
	cout << " 请输入你要去往的城市:" << endl;
	int city;
	cin >> city;

	//不断循环迭代,将每次循环的最优结果保存到routResult中
	while (1) {
		//随机化种子,用于生成随机数
		srand((unsigned)time(NULL));
		//开始进入迭代过程
		evolution(city);
		//每次迭代完成后,清空数组数据
		deleArrary();
		//判断键盘响应
		if (_kbhit()) {
			//如果读取到键盘按下'q'或'Q'键,则退出循环,结束整个过程
			if (tolower(_getch()) == 'q') {
				break;
			}
		}
	}


	//int x = 20;
	//while (x) {
	//	//随机化种子,用于生成随机数
	//	srand((unsigned)time(NULL));
	//	//开始进入迭代过程
	//	evolution(city);
	//	//每次迭代完成后,清空数组数据
	//	deleArrary();
	//	--x;
	//}

	//将所有保存的结果按照从小到大进行排序输出,并打印出最佳结果
	sortMap(routResult);
	return 0;
}
#pragma endregion



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值