⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsp.cpp

📁 结合均匀设计表和小边经验公式产生初始种群
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>


#define popsize 150  //种群大小
#define lchrom  15    //染色体的维数(即城市的个数)
#define termgen  5000  //进化终止代数

///////*****  全局变量的定义  *****///////
//////*****************************///////
struct individual     //定义个体+
{  unsigned chrom[lchrom];   //一条旅程(城市序列)
   double   fitness;         //个体适应度(即旅程距离)
};

struct      //最优个体
{  unsigned chrom[lchrom];    //最优个体的染色体
   double   bestfitness;      //最优个体适应度(即旅程距离的倒数)
   int      generation;       //最优个体生成代
}bestvidual;

double shortdis;//最短距离
struct individual pop[popsize];    //定义种群
struct individual tempop[popsize]; //选择、交叉操作时,用于临时存储种群
/*///20个城市
double x[lchrom]={5.294,4.286,4.719,4.185,0.915,4.771,1.524,3.447,3.718,2.649,
                  4.399,4.660,1.232,5.036,2.710,1.072,5.855,0.194,1.762,2.682};
double y[lchrom]={1.558,3.622,2.774,2.230,3.821,6.041,2.871,2.111,3.665,2.556,
                  1.194,2.949,6.440,0.244,3.140,3.454,6.203,1.862,2.693,6.097};
*////
///15个城市
double x[lchrom]={5.294,4.286,4.719,4.185,0.915,4.771,1.524,3.447,3.718,2.649,
                  4.399,4.660,1.232,5.036,2.710};
double y[lchrom]={1.558,3.622,2.774,2.230,3.821,6.041,2.871,2.111,3.665,2.556,
                  1.194,2.949,6.440,0.244,3.140};
///////
double dis[lchrom][lchrom];//任意两个城市间的距离(dis[i][j]表示城市[i]到城市[j]的距离)
double sumfitness;        //当前种群中个体适应度累计(总适应度)
double avgfitness;        //当前种群的平均适应度
double maxfitness;        //当前种群的最大适应度
int    cur_generation=0;    //当前世代数
unsigned portion=80;  //均匀分布表在种群中占的百分比
float  pc=0.65;    //交叉率
float  pm=0.03;   //变异率

FILE *fp;



/////////////////////////////////////////////////////////////////
////计算任意两个城市间的距离,存放在数组dis[lchrom][lchrom]中////
/////////////////////////////////////////////////////////////////
void dis_two()
{ int  i,j;
  for(i=0; i<lchrom-1; i++)
  {  dis[i][i]=0.0;
	 for(j=i+1; j<lchrom; j++)
	 { dis[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
       dis[j][i]=dis[i][j];
	 } 
  }
  dis[lchrom-1][lchrom-1]=0.0;
}
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////  
//// 求种群中每个个体的适应度fitness(即一条旅程的距离的倒数)//
////////////////////////////////////////////////////////////////
void fit()
{ int i,j;
  for(i=0;i<popsize;i++)
  {   pop[i].fitness=0.0;
	  for(j=0;j<lchrom-1;j++)
	      pop[i].fitness+=dis[pop[i].chrom[j]][pop[i].chrom[j+1]];
	  pop[i].fitness=1/(pop[i].fitness+dis[pop[i].chrom[lchrom-1]][pop[i].chrom[0]]);//回路
      //pop[i].fitness=1/pop[i].fitness; //不回路
  }	
}
////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////
///////////////        随机生成初始种群             ////////////
////////////////////////////////////////////////////////////////
//均匀分布表法

void inipop_table()
{ int table[lchrom][lchrom]
                           ={
	                      /*   {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19},
							 {0,2,4,6,8,10,12,14,16,18,1,3,5,7,9,11,13,15,17,19},
							 {0,3,6,9,12,15,18,1,4,7,10,13,16,19,2,5,8,11,14,17},
							 {0,4,8,12,16,1,5,9,13,17,2,6,10,14,18,3,7,11,19,15},
							 {0,5,10,15,2,7,12,17,4,9,14,19,1,6,11,16,3,8,13,18},
							 {0,6,12,18,1,7,13,19,2,8,14,3,9,15,4,10,16,5,11,17},
							 {0,7,14,5,12,19,3,10,17,1,8,15,6,13,4,11,18,2,9,16},
							 {0,8,16,1,9,17,2,10,18,3,11,19,4,12,5,13,6,14,7,15},
							 {0,9,18,4,13,8,17,3,12,7,16,2,11,6,15,1,10,19,5,14},
							 {0,10,7,17,4,14,1,11,8,18,5,15,2,12,9,19,6,16,3,13},
							 {0,11,10,9,8,19,7,18,6,17,5,16,4,15,3,14,2,13,1,12},
							 {0,12,1,13,2,14,3,15,4,16,5,17,6,18,7,19,8,9,10,11},
							 {0,13,3,16,6,19,9,12,2,15,5,18,8,11,1,14,4,17,7,10},
							 {0,14,5,19,10,1,15,6,11,2,16,7,12,3,17,8,13,4,18,9},
							 {0,15,7,14,6,13,5,12,4,19,11,3,18,10,2,17,9,1,16,8},
							 {0,16,9,2,18,11,4,13,6,15,8,1,17,10,3,19,12,5,14,7},
							 {0,17,11,5,16,10,4,15,9,3,14,8,2,19,13,7,1,18,12,6},
							 {0,18,13,8,3,16,11,6,1,19,14,9,4,17,12,7,2,15,10,5},
							 {0,19,15,11,7,13,18,14,10,6,2,17,3,9,5,1,16,12,8,4},
							 {0,17,14,11,8,5,2,19,16,13,10,7,4,1,18,15,12,9,6,3},
							}; //均匀分布表  */
							   {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14},
							   {0,2,4,6,8,10,12,14,1,3,5,7,9,11,13},
							   {0,3,6,9,12,1,4,7,10,13,2,5,8,11,14},
							   {0,4,8,12,3,7,11,2,6,10,14,1,5,9,13},
							   {0,5,10,3,8,13,1,6,11,4,9,14,2,7,12},
							   {0,6,12,1,7,13,2,8,14,3,9,4,10,5,11},
							   {0,7,14,4,11,1,8,5,12,2,9,6,13,3,10},
							   {0,8,7,6,14,5,13,4,12,3,11,2,10,1,9},
							   {0,9,1,10,2,11,3,12,4,13,5,14,6,7,8},
							   {0,10,3,13,6,9,2,12,5,8,1,11,4,14,7},
							   {0,11,5,10,4,9,3,14,8,2,13,7,1,12,6},
							   {0,12,7,2,14,9,4,11,6,1,13,8,3,10,5},
							   {0,13,9,5,1,14,10,6,2,11,7,3,12,8,4},
							   {0,14,11,8,5,2,13,10,7,4,1,12,9,6,3},
							   {0,13,11,9,7,5,3,1,14,12,10,8,6,4,2}};
  int num,tablenum;  //num:由均匀分布表生成的个体数
  bool mask[lchrom];  //mask[i]=0表示城市i还未产生过;mask[i]=1表示城市i还已产生
  int randnum[lchrom]; //存放生成的随机数
  int i,j,r,n,t;
  void delete_repeat();



 // printf("请输入均匀分布表在种群中占的百分比(0,20,40,60,80,100):");
  //scanf("%d",&portion);
 // printf("\n");

  for (n=0;n<popsize;n++)     //约定旅程起点为0号城市
     pop[n].chrom[0]=0;   
  mask[0]=1;  //起点城市0是固定的

  num=popsize*portion/100;
  tablenum=num/lchrom; 
  if(tablenum)  //将种群的前lchrom个个体赋值为均匀分布表
  { for(i=0;i<lchrom;i++)
	  for(j=1;j<lchrom;j++)
        pop[i].chrom[j]=table[i][j];
  }
 

 //由均匀分布表生成num个个体
 srand((unsigned)time(NULL));  //每次执行输出的结果不一样
  for(i=1;i<tablenum;i++)//生成tablenum-1个不同的随机序列(每个序列19个数),完成由均匀分布表生成的个体
  { for(j=1;j<lchrom;j++)
          mask[j]=0;
    for(j=1;j<lchrom;j++) //生成19个不同数(旅程起点0固定)构成一个随机序列
    { r=rand()%lchrom;
      while(mask[r])
         r=rand()%lchrom;
      mask[r]=1;
	  randnum[j]=r;
    }
	//lchrom个个体一组,即i循环一次就生成lchrom个个体
	int m;
	m=lchrom*i;
    for(j=0;j<lchrom;j++) //先将整个均匀变化表整个的复制过去
	  for(n=0;n<lchrom;n++)
		pop[m+j].chrom[n]=table[j][n];

    for(j=1;j<lchrom;j++) //从取随机数randnum[j],将均匀变化表中值为j的位置替换成randnum[j]
	{                     //第一列城市0是固定的,故j从1开始
	    for(n=0;n<lchrom;n++)//取一次数遍历一次均匀变化表(即每次要遍历lchrom个个体)
           for(t=1;t<lchrom;t++)
	          if(j==table[n][t])
			  {pop[m+n].chrom[t]=randnum[j];  break;}
	}
  }

 //随机生成剩余的popsize-num个个体
  for (n=num;n<popsize;n++)
  {	  for (i=1;i<lchrom;i++)     //将数组初始化为0,当产生的随机数等于数组下标后,将此数组对应的值变为1.
        mask[i]=0;           
      for (i=1;i<lchrom;i++)    //随机产生19个不同的随机数,与起点城市0共同代表一条旅程;
	   {  j=rand()%lchrom;
          while(mask[j])
             j=rand()%lchrom;
          mask[j]=1;
	      pop[n].chrom[i]=j;
		}
  }//至此,最初的popsize个初始种群完全生成

  fit();  //计算适应度
  delete_repeat();

}
///////////////////////////////////////////////
//判断种群中是否有相同的个体,若有,则删除相同的而再产生新的个体;直至种群中的个体各不相同
void delete_repeat()  
{   bool same; //same=1说明有相同的;same=0则没有相同的
    bool mask[lchrom]; ////mask[i]=0表示城市i还未产生过;mask[i]=1表示城市i还已产生
	int i,j,r,m;
	
	mask[0]=1; //旅程的起点城市0是固定的
	for(i=1;i<popsize;i++)
	{ do
		{ same=0;
          for(j=0;j<i;j++) //pop[i]与其前的(i-1)个个体进行比较看是否有相同的
		  { if(pop[i].fitness==pop[j].fitness)
			  { same=1;
                for(m=1;m<lchrom;m++)         
	               if(pop[i].chrom[m]!=pop[j].chrom[m])
				   { same=0; break;}
			  }
            if(same) //若有相同的,则重新产生个体,退出此次j循环的比较
			{ //以下重新产生个体
			  pop[i].fitness=0;
			  for (m=1;m<lchrom;m++) //将数组初始化为0,当产生的随机数等于数组下标后,将此数组对应的值变为1.
                mask[m]=0;           
              for (m=1;m<lchrom;m++)    //随机产生19个不同的随机数,与起点城市0共同代表一条旅程;
			  {  r=rand()%lchrom;
                 while(mask[r])
                   r=rand()%lchrom;
                 mask[r]=1;
	             pop[i].chrom[m]=r;
	             pop[i].fitness+=dis[pop[i].chrom[m-1]][pop[i].chrom[m]];  //不回路
			  }
	          pop[i].fitness=1/pop[i].fitness;
			  break;  //退出此次j循环的比较
			}
		  }
		}while(same);
	}
} 
void inipop()
{  bool mask[lchrom];          //标志数组,以保证产生的19个随机数不重复
  int  counter;               //计数器,用来控制产生300个不同的个体

  int  i,j,m,n;
  for (n=0;n<popsize;n++)     //约定旅程起点为0号城市
      pop[n].chrom[0]=0;   
  mask[0]=1;
 
  srand((unsigned)time(NULL));

  for (i=1;i<lchrom;i++)     //将数组初始化为0,当产生的随机数等于数组下标后,将此数组对应的值变为1.
       mask[i]=0;           
  for (i=1;i<lchrom;i++)    //随机产生19个不同的随机数,此序列代表一条旅程;
  { j=rand()%lchrom;
    while(mask[j])
      j=rand()%lchrom;
    mask[j]=1;
    for (n=0;n<popsize;n++) //将300个个体赋相同的值
       pop[n].chrom[i]=j;    
  }
 
  counter=1;  
  while(counter<popsize)    //随机产生要交换的位置号,产生不同的个体
  {  
	 mask[0]=0;      //上述产生19个不同的随机数后,mask的值均变成了1;在此,再
     mask[1]=0;      //次利用它产生不同的随机数。mask[i]的值为0说明i已产生过。
     j=rand()%lchrom;
     while(mask[j]==0)
      j=rand()%lchrom;
     mask[j]=0;

	 if(j>=17)
	 { for(i=1;i<=10;i++)  
	
	      for(m=i+1;m+1<j-4 ;m=m+2)
		  { pop[counter].chrom[i]=pop[0].chrom[j];
	        pop[counter].chrom[j]=pop[0].chrom[i];
		    pop[counter].chrom[j-2]=pop[0].chrom[m];
		    pop[counter].chrom[m]=pop[0].chrom[j-2];
			pop[counter].chrom[j-4]=pop[0].chrom[m+1];
		    pop[counter].chrom[m+1]=pop[0].chrom[j-4];
			counter++;
			if(counter==popsize) break;	 
		  } 
		 if(counter==popsize) break;	
	 }	 
     else
	 {
	 for(i=1;i<j;i++)   
	 { 
	   for(m=i+j,n=lchrom-1; (m<18)&&(m<n);m++,n--)
	   {    pop[counter].chrom[i]=pop[0].chrom[j];
	        pop[counter].chrom[j]=pop[0].chrom[i];
		    pop[counter].chrom[n]=pop[0].chrom[m];
		    pop[counter].chrom[m]=pop[0].chrom[n];
			pop[0].chrom[m+1]=pop[counter].chrom[m+1];
		    pop[counter].chrom[m+1]=pop[counter].chrom[m+2];
		    pop[counter].chrom[m+2]=pop[0].chrom[m+1];
			counter++;
			if(counter==popsize) break;	 
		}
			if(counter==popsize) break;	 
	  }		  
	 }
 } 

/////////////////////
// 直接循环产生
/*for (n=0;n<popsize;n++)
  { do
    { for (i=1;i<lchrom;i++)     //将数组初始化为0,当产生的随机数等于数组下标后,将此数组对应的值变为1.
        mask[i]=0;           
      for (i=1;i<lchrom;i++)    //随机产生19个不同的随机数,此序列代表一条旅程;
	   {  j=rand()%lchrom;
          while(mask[j])
             j=rand()%lchrom;
          mask[j]=1;
	      pop[n].chrom[i]=j;     
		}

      for (j=0;j<n;j++)       //确保刚生成的个体n与以前所有的个体均不同
	  { same=1;
        for(i=1;i<lchrom;i++)         
	    if(pop[n].chrom[i]!=pop[j].chrom[i])
		{ same=0; break;}
		if(same) break;   //若有相同的,则退出比较重新产生个体
	  }
	}while(same)

  }
 */
  fit();  //计算适应度
////////////////////
/* fprintf(fp,"随机生成的初始种群为:\n");
 for (i=0;i<popsize;i++)    //输出初始种群
  {for (j=0;j<lchrom;j++)
     fprintf(fp,"%d ",pop[i].chrom[j]);
   fprintf(fp,"\n");
  }*/
}
////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////  
////////***** 求当前种群的总适应度sumfitness     *****//////////
////////*****      及平均适应度avgfitness        *****//////////
//////*****   及最优个体bestvidual的染色体和适应度   ******/////
////////////////////////////////////////////////////////////////
void sum_avgfit(struct individual population[popsize])
{ int i,j;
  sumfitness=0;
  for(i=0;i<popsize;i++)
  { sumfitness+=population[i].fitness;  //总适应度
    if(population[i].fitness>bestvidual.bestfitness)   //求最优个体
	  { bestvidual.generation=cur_generation;
		bestvidual.bestfitness=population[i].fitness;
	    for(j=0;j<lchrom;j++)
            bestvidual.chrom[j]=population[i].chrom[j];
	  }
  }
  avgfitness=sumfitness/popsize;  //平均适应度
 
 ///(测试)
//  fprintf(fp,"\n总适应度为:%f; 平均适应度为:%f\n",sumfitness,avgfitness);
///
}

////////////////////////////////////////////////////////////////  
///////****      选择操作(轮盘赌方法)select()     ***/////////
///////****     选择后的个体转移到了种群tempop中    ***/////////
////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -