蚁群算法解决TSP问题 再续

之前的文章

还是参数问题,上次考虑为了使浓度高的较劣路径能早点消失,使用一个值来判断浓度,较大浓度则有很大概率出错消失,后来想想,不符合蚁群算法的原理。然后真正的做法是使出错概率较小,这样才能保证对于单独沿路径前进的蚂蚁不至于有很大概率出错。而之前两次,我都将出错概率设的值较大,为10%,则蚂蚁在10个城市内极大可能会出错的。

然后这样做之后的效果还是很不错的,但是还是没有完全的解决问题,但是我感觉这最后没有解决的部分可能是我测试数据的问题吧,我使用的数据,两个之间的距离都不想等。。。。这样路径的选择性太大,而导致蚂蚁对前一部分路径的收敛完全无法改变后一部分的路径不是最佳的情况,导致其收敛即浪费时间,又会影响后部分路径的收敛。





#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <time.h>


using namespace std;
//使用10个蚂蚁,进行10个城市的TSP问题求解。
const int MMax = 9999;//蚂蚁数量,蚂蚁数量根据城市数量决定。
const int NMax = 500;//城市数量最大数量,超过出错
int m,n;//蚂蚁数量与城市数量
const double Q = 25 ;//常量
const int K = 10000;//循环总次数
int D[NMax][NMax];//路径长度
double Phe[NMax][NMax];//边对应的信息素浓度
int LK;//蚂蚁此循环中的总路径长度
int Path[MMax][NMax];//记录蚂蚁的路径,用于防止走重复的路。记录的是点
int ant;//蚂蚁当前所在点
int i,j,k,p,q;//循环使用
double Dis = 0.45;//每次信息素 消失的速率
int sameNum,samePhe[NMax];//每次去寻找信息素最多的边,如初始情况,信息素量都相同时,要
//随机的去从中选取边。
int bugNum,bugTry[NMax];//出错情况下进行的选择
double bugP = 0.02;//每一次操作的出错概率
//后来发现,出错概率要结合蚂蚁数与城市数进行判断,而定值Q为估计距离
int start;//出发点,城市编号从0 - n-1.
double Max;//用来选取最多信息素的边
bool Passed[NMax];//用来判断城市是否已经经过,是否可以选取

int bNum,Branch[NMax];//所有可以被选择的分支数量与编号
double rPhe,BPhe[NMax];//对应分支所对应的信息素浓度,BPhe[n]=Phe[i][Branch[0]]+...+PPhe[i][Branch[n]]
//然后判断 rPhe = rand() / PheAll 位于何处。。。即为随机确定的分支,这里本来应该按比例分配的直接使用随机数进行分配
double MIN = 1;//当Phe小于2时,进行忽略
int main()
{

	//载入数据
	fstream f("data.txt",ios::in);
	f >> n;
	if( n > NMax)//本来想直接赋值,后来又决定从文件中读入。
		return 0;
	for(i = 0;i<n;i++)
		for(j = 0;j<n ;j++)
			if(j != i)
				f>>D[i][j];
	for(i = 0;i < n;i++)
		D[i][i] = 0;
	f >> start;
	if(start > n-1)return 0;//没必要的检测,如果文件未正确书写,发生意外的错误,概不负责。
	f.close();
	

	for(i = 0;i < n;i++)
		for(j = 0; j < n;j++) 
			Phe[i][j] = 3;//初始化每条边上的信息素浓度
	for(i = 0; i < n;i++)
		Phe[i][i] = 0;
	for(i = 0;i< m;i++)
		Path[i][0] = start;//每只蚂蚁的出发点都固定
	m = 100;//蚂蚁数为城市数的2倍,后来发现不够
	for(k = 0;k < K;k++){
		srand((unsigned)time(NULL)); 
		for(i = 0;i < m;i++){//对于每只蚂蚁,进行一次循环	
			ant = start;
			for(j = 0;j < n;j++)
				Passed[j] = false;
			Passed[ant] = true;
			for(j = 1;j < n;j++){//每只蚂蚁选n-1次边
					bNum = 0;
					bugNum = 0;
					rPhe = 0;
					for(p = 0; p < n ;p ++){
						if(!Passed[p]){
							if(Phe [ant][p] > MIN){					
								rPhe += Phe[ant][p] ;
								BPhe [bNum] = rPhe;
								Branch [bNum++] = p ;//将这些数据读入并保存
							}else{
								Phe[ant][p] = 0;
								bugTry[bugNum++] = p;
							}
						}
					}
					if(bugNum == 0){
						for(p = 0;p < n;p++)
							if(!Passed [p])
								bugTry[bugNum++] = p;

					}
						
						rPhe = (double) rand()/32765 *rPhe;
						for(p = 0; p < bNum - 1;p++)
							if(rPhe < BPhe[p])//使用概率进行分配
								break;
						q = Branch[p];
						///if(bNum < 1)
						//	cout<<endl;

						if(bNum == 0 )
							q = bugTry[ rand() % bugNum];
						else {
							if( (double)rand() / 32765 < bugP)
								q = bugTry[ rand() % bugNum];
						}
				ant = q;
				Passed[ant] = true;//路径经过
				Path[i][j] = ant;//保存路径
			}
		}
		for(i = 0;i < n;i++)
			for(j = 0; j < n;j++) 
				Phe[i][j] *= Dis ;//每次循环后,进行信息素的消逝
		//完成对每一个蚂蚁的操作后,进行增加信息素的操作,使用Ant-Circle System 
		p = 99999;
		for(i = 0; i < m;i++){
			LK  = 0 ;
			for(j = 0; j < n-1;j++)
				LK += D[Path[i][j]][Path[i][j+1]];//计算一次循环中蚂蚁的总路程
			LK += D[Path[i][j]][Path[i][0]];//回到初始点
			for(j = 0; j < n-1;j++)
				Phe[Path[i][j]][Path[i][j+1]] += Q/LK ;
			Phe[Path[i][j]][Path[i][0]] += Q/LK ;//初始点
			if(LK < p){
			p = LK;
			q = i;
		}
		}		
	}
	p = 0xfffff;//虽然已经完成操作,但我们要直观的从所有现有路径中找出最短的路径。
	LK = 0;
	for(i = 0;i < n;i++)
		Passed[i] = false;
	
	for(i = 0;i < n-1;i++){
		Max = 0;	
		Passed[start] = true;
		for(j = 0;j < n;j++)
			if(!Passed[j])
				Max = Max > Phe[start][j] ? Max : Phe[start][j];
		for(j = 0 ;j < n;j++)
			if(Phe[start][j] == Max && !Passed[j]){
				LK += D[start][j];
				Path[0][i+1] = j;
				start = j;
			}
	}
	LK += D[Path[0][0]][0];
	for(i = 0;i < n; i++)
		cout << Path[0][i]<<"->";
	cout << Path[0][0]<<'\n'<<LK<<endl;
 	return 0;
}






  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值