问题为:30城市TSP问题(d*=423.741 by D B Fogel)TSP Benchmark 问题
城市坐标:
41 94;37 84;54 67;25 62;7 64;2 99;68 58;71 44;5462;83 69;64 60;18 54;2260;83 46;91 38;25 38;2442;58 69;71 71;74 78;8776;18 40;13 40;82 7;62 32;58 35;45 21;41 26;44 35;4 50
程序为:
采用轮盘赌选择、基于位置交叉PBX、两点互换变异
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<cmath>
#include<cstdio>
using namespace std;
const int M=100,T=500,N=30;//种群大小和迭代次数和城市个数
const double pc=0.6,pm=0.05;//交叉率、变异率
int condition[30][2]={
{41,94},{37,84},{54,67},{25,62},{7,64},{2,99},{68,58},{71,44},{54,62},{83,69},
{64,60},{18,54},{22,60},{83,46},{91,38},{25,38},{24,42},{58,69},{71,71},{74,78},
{87,76},{18,40},{13,40},{82,7},{62,32},{58,35},{45,21},{41,26},{44,35},{4,50}
};//30个城市的坐标
struct chromo//构造染色体
{
int code[N];
double fit;
double sumfit;
};
chromo p[M];//定义一个种群
chromo fitmax,fitmin;//一个种群中的最长路径和最短路径的染色体个体
int min,max;
double randab(double a,double b) //在区间(a,b)内生成一个随机数
{
double c,r;
c=b-a;
r=a+c*rand()/(RAND_MAX+1.0);
return r;
}
void initial();//初始化函数
void evluate();//计算适值的函数
void print();//显示函数
void select();//选择函数
void crossover();//交叉函数
void mutation();//变异函数
void main()
{
cout<<"初始化种群:"<<endl;
initial();
evluate();
print();
int gen=1;//迭代次数
while(gen<=T)
{
cout<<"第"<<gen<<"次迭代"<<endl;
select();
evluate();
crossover();
evluate();
mutation();
evluate();
print();
gen++;
}
system("pause");
}
/******种群的初始化********/
void initial()
{
int i,j,k;
double squence[2][N],temp;
srand((unsigned)time(NULL));
for(k=0;k<M;k++)
{
for(i=0;i<N;i++)
{
squence[0][i]=randab(0,1);//二维数组的第一位存放生成的随机数
squence[1][i]=i+1;//第二维放城市的号码
}
for(i=0;i<N;i++)//按照随机数的由大到小顺序随机排列城市
{
for(j=i+1;j<N;j++)
{
if(squence[0][i]<squence[0][j])
{
temp=squence[0][i];
squence[0][i]=squence[0][j];
squence[0][j]=temp;
temp=squence[1][i];
squence[1][i]=squence[1][j];
squence[1][j]=temp;
}
}
}
for(j=0;j<N;j++)
p[k].code[j]=(int)squence[1][j];
}
}
/*********计算适值函数*********/
void evluate()
{
int i,j,a,b;
for(i=0;i<M;i++)
{
p[i].fit=0;
p[i].sumfit=0;
for(j=0;j<N-1;j++)//每一个染色体的适应值是所有点按顺序之间的距离之和
{
a=p[i].code[j];
b=p[i].code[j+1];
p[i].fit+=sqrt(pow((double)(condition[b][0]-condition[a][0]),2.0)+pow((double)(condition[b][1]-condition[a][1]),2.0));
}
p[i].fit+=sqrt(pow((double)(condition[0][0]-condition[N-1][0]),2.0)+pow((double)(condition[0][1]-condition[N-1][1]),2.0));
}
p[0].sumfit=p[0].fit;
for(i=1;i<M;i++)
{
p[i].sumfit=p[i-1].sumfit+p[i].fit;
}
}
/**********显示函数*********/
void print()
{
int i,min,max;
fitmin.fit=p[M-1].sumfit;
fitmax.fit=0;
for(i=0;i<M;i++)
{
if(fitmin.fit>p[i].fit)
{
fitmin=p[i];
min=i;
}
if(fitmax.fit<p[i].fit)
{
fitmax=p[i];
max=i;
}
}
cout<<"当前种群中最短路径的顺序为:"<<endl;
for(i=0;i<N;i++)
cout<<fitmin.code[i]<<" ";
cout<<"当前种群中最短路径的距离为:"<<endl;
cout<<fitmin.fit<<endl;
cout<<"当前种群中最长路径的顺序为:"<<endl;
for(i=0;i<N;i++)
cout<<fitmax.code[i]<<" ";
cout<<"当前种群中最长路径的距离为:"<<endl;
cout<<fitmax.fit<<endl;
}
/*********选择函数*********/
void select()
{
int i,j;
double s;
chromo pt[M];
srand((unsigned)time(NULL));
p[0].sumfit=fitmax.fit*1.1-p[0].fit;//采用轮盘赌选择
for(i=1;i<M;i++)
{
p[i].sumfit=p[i-1].sumfit+fitmax.fit*1.1-p[i].fit;
}
for(i=0;i<M;i++)
{
s=randab(p[0].sumfit,p[M-1].sumfit);
for(int j=0;j<M;j++)
{
if(p[j].sumfit>=s)
{
pt[i]=p[j];
break;
}
else continue;
}
}
for(i=0;i<M;i++)
p[i]=pt[i];
}
/*********交叉函数**********/
void crossover()
{
int i,j,k,t,s;
int te[N];
chromo po[M];
for(i=0;i<M;i++)
for(j=0;j<N;j++)
po[i].code[j]=0;
srand((unsigned)time(NULL));
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)//数组te记录子代染色体的某个位置是否已经有基因
te[j]=0;
double q=randab(0,1);
if(q<pc)
{
for(j=0;j<M;j++)//随机选择交叉对象为第t个染色体
{
t=rand()%M;
if(t!=i)
break;
}
for(j=0;j<N/2;j++)
{
s=rand()%N;//pbx 在父代1上随机取N/2个位置,s为位置
if(te[s]!=0)//取得位置重复的话重新取
{
j--;
continue;
}
else
{
te[s]=1;//记录这个位置被取过了
po[i].code[s]=p[i].code[s];//对应位置的基因放入子代
}
}
for(j=0;j<N;j++)
{
for(k=0;k<N;k++)
{
if(p[t].code[j]==po[i].code[k])
break;
}//找出父代2中子代还没有的基因
if(k==N)
{
for(int l=0;l<N;l++)
{
if(te[l]==0)//子代还没有基因的位置
{
po[i].code[l]=p[t].code[j];
te[l]=1;
break;
}
}
}
}
}
else
po[i]=p[i];
}
for(i=0;i<M;i++)
p[i]=po[i];
}
/********变异函数********/
void mutation()
{
int i,j,c1,c2,temp;
double q;
srand((unsigned)time(NULL));
for(i=0;i<M;i++)
{
q=randab(0,1);
if(q<pm)
{
for(j=0;j<2;j++)
{
c1=rand()%N;//随机选取两个位置,交换位置
c2=rand()%N;
if(c2==c1)
{
j--;
continue;
}
else break;
}
temp=p[i].code[c1];
p[i].code[c1]=p[i].code[c2];
p[i].code[c2]=temp;
}
else continue;
}
}