蚁群算法(ACA)解TSP代码

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

#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

你可能感兴趣的:(TSP,蚁群算法,ACA,组合优化问题,智能优化算法)