蚁群算法(ACA)解TSP代码

/***************************************************************
 * 程序名称: 针对TSP组合优化问题人工蚁群算法(ACA_TSP)
 * 编译环境: Visual C++ 6.0
 * 交流方式: Email (junh_cs@126.com)
 ***************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>

/**************************************************************/
#define CITY_NUM		30			//表示城市数目
#define ANT_NUM			10			//表示蚂蚁数目
#define ITERITIVE_NUM	400			//表示迭代的次数
#define POSITION_DIM	2			//表示城市坐标的维度
#define FCITY_INDEX		0			//用来表示初始城市的下标(目前只能等于0,后期改进)
// 下面的参数选取对结果有很大的影响
#define AILFA			5			//用来表示信息素在计算转移概率的重要性
#define BETA			4			//用来表示能见度(距离信息)在计算转移概率的重要性
#define VOLATIE_FACTOR	0.08			//挥发因子在0到1之间
#define INIT_PHEROMONE	0.1			//每个边的初始信息素含量

/*
//在DATA30.dat上调的参数
#define CITY_NUM		30			//表示城市数目
#define ANT_NUM			10			//表示蚂蚁数目
#define ITERITIVE_NUM	400			//表示迭代的次数
#define POSITION_DIM	2			//表示城市坐标的维度
#define FCITY_INDEX		0			//用来表示初始城市的下标(目前只能等于0,后期改进)
// 下面的参数选取对结果有很大的影响
#define AILFA			4			//用来表示信息素在计算转移概率的重要性
#define BETA			3			//用来表示能见度(距离信息)在计算转移概率的重要性
#define VOLATIE_FACTOR	0.08		//挥发因子在0到1之间
#define INIT_PHEROMONE	0.1			//每个边的初始信息素含量
//0->17->1->9->13->27->6->16->21->11->24->3->7->8->28->15->14->22->20->12->10->4->29->23->5->25->18->26->19->2->0
//total_distance = 420.794632
*/
/**************************************************************/
// 定义个全局变量
double city_pos[CITY_NUM][POSITION_DIM];			//存储city的坐标信息
double pheromone[CITY_NUM][CITY_NUM];				//存储cityA到cityB边的信息素
double city_dis[CITY_NUM][CITY_NUM];				//存储cityA到cityB的距离,即:能见度
int local_road_info[CITY_NUM+1];					//存储此次最好(最短)路径 (默认都是文件读入的编号开始)
int global_road_info[CITY_NUM+1];					//存储此次最好(最短)路径 (默认都是文件读入的编号开始)
double local_road_dis = 9999999999;					//存储最好(最短)路径长度
double global_road_dis = 9999999999;				//存储最好(最短)路径长度
int tag_old[ANT_NUM][CITY_NUM];						//存储每只蚂蚁走过了哪些路,走过用1,没走过用0
/**************************************************************/
//函数预定义区域
double calculate_Pij(int ant, int cityA, int cityB);		//计算ant从cityA转移cityB概率
void initialize();											//初始化环境
void init_tag_old();										//初始化tag_old变量
double odistance(double *a, double *b, int vector_len);		//计算两个城市之间距离
void findOneTimeFood();										//模拟人工蚁群一次找食物的过程
void update_pheromone_matrix();								//根据global_road信息跟新信息素
double rand_select_value(double under, double upper);		//从[under, upper]之间产生一个随机数
int is_ij_int_global_road(int i, int j);					//判断ij在不在全局最优路径中
void search_short_road();									//找到全局最优的路径

void print_cmd();											//在命令行端输出最短路径和路径长度
void print_file(double seconds, char* file_path);					//在文件中输出最短路径和路径长度
/**************************************************************/

void main(){
	int k;
	int i;
	FILE *fp;
	float x;
	float y;
	clock_t start;
	clock_t end;

	srand(time(NULL));						//初始化随机种子


	for (k = 0; k < 20; k++){
		// read city position (x, y)
		fp=fopen("DATA30.dat","r");
		for(i = 0; i < CITY_NUM; i++){
			fscanf(fp,"%f %f",&x, &y);
			printf("%f, %f\n", x, y);
			city_pos[i][0]= x;
			city_pos[i][1]= y;
		}
		fclose(fp);
		
		
		start=clock();	//记录程序开始运行的时间
		initialize();
		search_short_road();
		end=clock();	//记录程序运行结束的时间
		print_file(1.0*(end-start)/1000, "实验结果.txt");
	}

}

/**************************************************************
 * @function:	初始化变量,构建初始化状态
 **************************************************************/
void initialize(){
	int i;
	int j;
	
	// average the pheromone value to per edge
	// calculate the distance of each edge
	for (i = 0; i < CITY_NUM; i++){
		pheromone[i][i] = INIT_PHEROMONE;
		for (j = 0; j < i; j++){		//i-i是在tag_old中标记不会出现的
			city_dis[i][j] = odistance(city_pos[i], city_pos[j], POSITION_DIM);
			city_dis[j][i] = city_dis[i][j];	//这里的距离都是相等的

			pheromone[i][j] = pheromone[j][i] = INIT_PHEROMONE; //约等于0
		}
	}

	// initialize the tag_old array
	init_tag_old();
	global_road_dis = 9999999999;
	local_road_dis = 9999999999;	
}

/**************************************************************
 * @function:	初始化tag_old变量
 **************************************************************/
void init_tag_old(){
	int i;
	int j;
	for (i = 0; i < ANT_NUM; i++){
		tag_old[i][0] = 1;
		for (j = 1; j < CITY_NUM; j++){
			tag_old[i][j] = 0;
		}
	}
}

/**************************************************************
 * @function:	找到最好的路径
 **************************************************************/
void search_short_road(){
	int i;
	int times = 0;
	while (times < ITERITIVE_NUM){
		// 找当前全局最好的路径
		findOneTimeFood();
		if (local_road_dis < global_road_dis){
			global_road_dis = local_road_dis;
			for (i = 0; i < CITY_NUM+1; i++){
				global_road_info[i] = local_road_info[i];
			}
		}//end_if
		printf("the %d iteritive: \n", times);
		print_cmd();
		// update the pheromone matrix
		update_pheromone_matrix();

		times++;
	}//end_while
}

/**************************************************************
 * @function:	更新信息素矩阵
 **************************************************************/
void update_pheromone_matrix(){
	int i;
	int j;
	for (i = 0; i < CITY_NUM; i++){
		for (j = 0; j < CITY_NUM; j++){
			if (1 == is_ij_int_global_road(i, j)){	//在全局最优路径中
				pheromone[i][j] = (1-VOLATIE_FACTOR)*pheromone[i][j] 
					+ VOLATIE_FACTOR / global_road_dis;
			}else{	//不在全局最优路径中
				pheromone[i][j] = (1-VOLATIE_FACTOR)*pheromone[i][j];
			}
		}
	}
}	

/**************************************************************
 * @function:	判断ij边在不在global_road中
 **************************************************************/
int is_ij_int_global_road(int i, int j){
	int k;
	int ans = 0;
	for (k = 0; k < CITY_NUM; k++){
		if (i == global_road_info[k] 
			&& j == global_road_info[k+1]){
			ans = 1;
			break;
		}
	}

	return ans;
}

/**************************************************************
 * @function:	模拟人工蚁群一次找食物的过程 (还是需要修改的)
 **************************************************************/
void findOneTimeFood(){
	int i;
	int j;
	int k;	
	int next_city; //可以表示当前蚂蚁选择的下一个城市下标
	double next_city_pro[CITY_NUM];		//存储每一只蚂蚁去下一个城市的概率
	int now_road[CITY_NUM+1];			//存储每一只蚂蚁找到的路径
	double now_road_dis;
	init_tag_old();						//在每次出动的时候,历史信息都将初始化
	local_road_dis = 9999999999;	//初始化local_road_diss
	for (i = 0; i < ANT_NUM; i++){
		// 计算第i只蚂蚁走的路
		now_road[0] = 0;
		now_road_dis = 0.0;
		for (j = 1; j < CITY_NUM; j++){ //决策CITY_NUM-1次
			// 计算第i只蚂蚁去每一个城市的概率
			// 并以直方图累加的形式存储在next_city_pro中
			next_city_pro[0] = 0.0;
			for (k = 1; k < CITY_NUM; k++){
				double tmp = calculate_Pij(i, now_road[j-1], k);
				next_city_pro[k] = next_city_pro[k-1] + tmp;
			}

			// 产生一个随机数看其落在哪一个区间
			double rd = rand_select_value(0.0, 1.0-0.000001); //-0.000001? 确保每个城市都能走到
			for (next_city = 1; next_city < CITY_NUM; next_city++){ //next_city=1? 因为第0个城市已经走过了
				if (rd < next_city_pro[next_city]){
					break;	//k里面存储了第i只蚂蚁的选择下一个城市目标
				}
			}
			
			tag_old[i][next_city] = 1;
			now_road[j] = next_city;
			now_road_dis += city_dis[now_road[j-1]][next_city];
		}
		now_road[CITY_NUM] = 0;
		now_road_dis += city_dis[now_road[next_city]][0];
		if (now_road_dis < local_road_dis){
			local_road_dis = now_road_dis;
			for (k = 0; k < CITY_NUM+1; k++){
				local_road_info[k] = now_road[k];
			}
		}
	}
}

/**************************************************************
 * @function:	计算ant从cityA转移cityB概率
 **************************************************************/
double calculate_Pij(int ant, int now_city, int aim_city){
	double ans = 0.0;
	double sum = 0.0;
	int i;
	if (0 == tag_old[ant][aim_city]){
		for (i = 0; i < CITY_NUM; i++){
			if (0 == tag_old[ant][i]){
				sum += (pow(pheromone[now_city][i], AILFA)
					*pow(1/city_dis[now_city][i], BETA));
			}
		}
		
		double tmp = pow(pheromone[now_city][aim_city], AILFA)*pow(1/city_dis[now_city][aim_city], BETA);
		ans = tmp/sum;		
	}
	return ans;
}

/**************************************************************
 * @function:	计算两个向量之间的距离
 * @notice :	两个向量a与b必须是vector_len长度
 **************************************************************/
double odistance(double *a, double *b, int vector_len){
	double ans = 0;
	int i;
	for (i = 0; i < vector_len; i++){
		ans += (*(a+i)-*(b+i)) * (*(a+i)-*(b+i));
	}

	ans = sqrt(ans);

	return ans;
}


/**************************************************************
 * @function:	该函数是在[under, upper]区间中随机
 *				选择一个值
 **************************************************************/
double rand_select_value(double under, double upper){
	if(under>upper) {
		printf("\nerror:\t[%d, %d] is invalid region!", under, upper);
		exit(1);
	}
	double lamta = (double)rand()/(RAND_MAX);
	return (under+(upper-under)*lamta); 
}


/**************************************************************
 * @function:	该函数主要是判断两个等长的a向量和b向量是不是一样的
 *				如果一样了返回1, 否则返回0
 **************************************************************/
int is_same_vector(double* a, double* b, int len){
	int ans = 1, i;
	for (i = 0; i < len; i++){
		if (a[i] != b[i]){
			ans = 0;
			break;
		}
	}

	return ans;
}

/**************************************************************
 * @function:	在命令行输出伪次优路径,和路径总长度
 **************************************************************/
void print_cmd(){
	int i;
	for (i = 0; i < CITY_NUM; i++){
		printf("%d->", global_road_info[i]);
	}
	printf("%d\ntotal_distance = %.6f\n", global_road_info[CITY_NUM], global_road_dis);
}

/**************************************************************
 * @function:	在文件中出伪次优路径,和路径总长度
 **************************************************************/
void print_file(double seconds, char* file_path){
	FILE *fp = fopen(file_path, "a");	
	int i;
	for (i = 0; i < CITY_NUM; i++){
		fprintf(fp, "%d->", global_road_info[i]);
	}
	fprintf(fp, "%d\n总距离为: %.6f\n", global_road_info[CITY_NUM], global_road_dis);
	fprintf(fp, "%d次迭代共花: %.2f秒\n", ITERITIVE_NUM, seconds);
	fclose(fp);
}


 

//给出DATA30.DAT 测试数据

//(x, y)表示城市的坐标

54 62
58 69
71 71
45 21
25 62
37 84
83 46
41 26
44 35
64 60
22 60
62 32
18 54
68 58
18 40
24 42
91 38
54 67
74 78
83 69
 4 50
82  7
13 40
 2 99
58 35
41 94
87 76
71 44
25 38
 7 64

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
n=size(C,1);%n表示问题的规模(城市个数) D=zeros(n,n);%D表示完全图的赋权邻接矩阵 for i=1:n for j=1:n if i~=j D(i,j)=((C(i,1)-C(j,1))^2+(C(i,2)-C(j,2))^2)^0.5; else D(i,j)=eps; %i=j时不计算,应该为0,但后面的启发因子要取倒数,用eps(浮点相对精度)表示 end D(j,i)=D(i,j); %对称矩阵 end end Eta=1./D; %Eta为启发因子,这里设为距离的倒数 Tau=ones(n,n); %Tau为信息素矩阵 Tabu=zeros(m,n); %存储并记录路径的生成 NC=1; %迭代计数器,记录迭代次数 R_best=zeros(NC_max,n); %各代最佳路线 L_best=inf.*ones(NC_max,1); %各代最佳路线的长度 L_ave=zeros(NC_max,1); %各代路线的平均长度 while NC<=NC_max %停止条件之一:达到最大迭代次数,停止 %%第二步:将m只蚂蚁放到n个城市上 Randpos=[]; %随即存取 for i=1:(ceil(m/n)) Randpos=[Randpos,randperm(n)]; end Tabu(:,1)=(Randpos(1,1:m))'; %此句不太理? %%第三步:m只蚂蚁按概率函数选择下一座城市,完成各自的周游 for j=2:n %所在城市不计算 for i=1:m visited=Tabu(i,1:(j-1)); %记录已访问的城市,避免重复访问 J=zeros(1,(n-j+1)); %待访问的城市 P=J; %待访问城市的选择概率分布 Jc=1; for k=1:n if length(find(visited==k))==0 %开始时置0 J(Jc)=k; Jc=Jc+1; %访问的城市个数自加1 end end %下面计算待选城市的概率分布 for k=1:length(J) P(k)=(Tau(visited(end),J(k))^Alpha)*(Eta(visited(end),J(k))^Beta); end P=P/(sum(P)); %按概率原则选取下一个城市 Pcum=cumsum(P); %cumsum,元素累加即求和 Select=find(Pcum>=rand); %若计算的概率大于原来的就选择这条路线 to_visit=J(Select(1)); Tabu(i,j)=to_visit; end end if NC>=2 Tabu(1,:)=R_best(NC-1,:); end %%第四步:记录本次迭代最佳路线 L=zeros(m,1); %开始距离为0,m*1的列向量 for i=1:m R=Tabu(i,:); for j=1:(n-1) L(i)=L(i)+D(R(j),R(j+1)); %原距离加上第j个城市到第j+1个城市的距离 end L(i)=L(i)+D(R(1),R(n)); %一轮下来后走过的距离 end L_best(NC)=min(L); %最佳距离取最小 pos=find(L==L_best(NC)); R_best(NC,:)=Tabu(pos(1),:); %此轮迭代后的最佳路线 L_ave(NC)=mean(L); %此轮迭代后的平均距离 NC=NC+1 %迭代继续 %%第五步:更新信息素 Delta_Tau=zeros(n,n); %开始时信息素为n*n的0矩阵 for i=1:m for j=1:(n-1) Delta_Tau(Tabu(i,j),Tabu(i,j+1))=Delta_Tau(Tabu(i,j),Tabu(i,j+1))+Q/L(i); %此次循环在路径(i,j)上的信息素增量 end Delta_Tau(Tabu(i,n),Tabu(i,1))=Delta_Tau(Tabu(i,n),Tabu(i,1))+Q/L(i); %此次循环在整个路径上的信息素增量 end Tau=(1-Rho).*Tau+Delta_Tau; %考虑信息素挥发,更新后的信息素 %%第六步:禁忌表清零 Tabu=zeros(m,n); %%直到最大迭代次数 end %%第七步:输出结果 Pos=find(L_best==min(L_best)); %找到最佳路径(非0为真) Shortest_Route=R_best(Pos(1),:) %最大迭代次数后最佳路径 Shortest_Length=L_best(Pos(1)) %最大迭代次数后最短距离 subplot(1,2,1) %绘制第一个子图形 DrawRoute(C,Shortest_Route) %画路线图的子函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jun-H

你的鼓励是我创作的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值