遺傳演算法解決TSP問題

老司機的詩和遠方發表於2020-04-06

遺傳演算法(Genetic Algorithm)是模擬達爾文生物進化論的自然選擇和遺傳學機理的生物進化過程的計算模型,是一種通過模擬自然進化過程搜尋最優解的方法

遺傳演算法的基本運算過程如下:

a)初始化:設定進化代數計數器t=0,設定最大進化代數T,隨機生成M個個體作為初始群體P(0)。

b)個體評價:計算群體P(t)中各個個體的適應度。

c)選擇運算:將選擇運算元作用於群體。選擇的目的是把優化的個體直接遺傳到下一代或通過配對交叉產生新的個體再遺傳到下一代。選擇操作是建立在群體中個體的適應度評估基礎上的。

d)交叉運算:將交叉運算元作用於群體。所謂交叉是指把兩個父代個體的部分結構加以替換重組而生成新個體的操作。遺傳演算法中起核心作用的就是交叉運算元。

e)變異運算:將變異運算元作用於群體。即是對群體中的個體串的某些基因座上的基因值作變動。

群體P(t)經過選擇、交叉、變異運算之後得到下一代群體P(t 1)。

f)終止條件判斷:若t=T,則以進化過程中所得到的具有最大適應度個體作為最優解輸出,終止計算。

下面用C語言模擬遺傳演算法模擬TSP問題

TSP問題及旅行商問題,假設有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最後要回到原來出發的城市。路徑的選擇目標是要求得的路徑路程為所有路徑之中的最小值

交叉的演算法如下圖


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#define cities 10  //城市的個數
#define MAXX 100//迭代次數
#define pc 0.8 //交配概率
#define pm 0.05 //變異概率
#define num 10//種群的大小
int bestsolution;//最優染色體
int distance[cities][cities];//城市之間的距離
struct group  //染色體的結構
{
	int city[cities];//城市的順序
	int adapt;//適應度
	double p;//在種群中的倖存概率
}group[num],grouptemp[num];
//隨機產生cities個城市之間的相互距離
void init()
{
	int i,j;
	memset(distance,0,sizeof(distance));
	srand((unsigned)time(NULL));
    for(i=0;i<cities;i++)
	{
	    for(j=i+1;j<cities;j++)
		{
		   distance[i][j]=rand()%100;
		   distance[j][i]=distance[i][j];
		}
	}
	//列印距離矩陣
	printf("城市的距離矩陣如下\n");
	for(i=0;i<cities;i++)
	{
		for(j=0;j<cities;j++)
		printf("%4d",distance[i][j]);
		printf("\n");
	}
}
//隨機產生初試群
void groupproduce()
{
	int i,j,t,k,flag;
	for(i=0;i<num;i++)  //初始化
	for(j=0;j<cities;j++)
	group[i].city[j]=-1;
	srand((unsigned)time(NULL));
    for(i=0;i<num;i++)
	{
		//產生10個不相同的數字
		for(j=0;j<cities;)
		{
			t=rand()%cities;
			flag=1;
			for(k=0;k<j;k++)
			{
				if(group[i].city[k]==t)
				{
					flag=0;
					break;
				}
			}
			if(flag)
			{
				group[i].city[j]=t;
				j++;
			}
		}
	}
	//列印種群基因
	printf("初始的種群\n");
	for(i=0;i<num;i++)
	{
		for(j=0;j<cities;j++)
		printf("%4d",group[i].city[j]);
		printf("\n");
	}
}
//評價函式,找出最優染色體
void pingjia()
{
	int i,j;
	int n1,n2;
	int sumdistance,biggestsum=0;
	double biggestp=0;
	for(i=0;i<num;i++)
	{
		sumdistance=0;
		for(j=1;j<cities;j++)
		{
			n1=group[i].city[j-1];
			n2=group[i].city[j];
			sumdistance+=distance[n1][n2];
		}
		group[i].adapt=sumdistance; //每條染色體的路徑總和
		biggestsum+=sumdistance; //種群的總路徑
	}
	//計算染色體的倖存能力,路勁越短生存概率越大
	for(i=0;i<num;i++)
	{
		group[i].p=1-(double)group[i].adapt/(double)biggestsum; 
		biggestp+=group[i].p;
	}
	for(i=0;i<num;i++)
	group[i].p=group[i].p/biggestp;  //在種群中的倖存概率,總和為1
	//求最佳路勁
	bestsolution=0;
	for(i=0;i<num;i++)
	if(group[i].p>group[bestsolution].p)
	bestsolution=i;
	//列印適應度
	for(i=0;i<num;i++)
	printf("染色體%d的路徑之和與生存概率分別為%4d  %.4f\n",i,group[i].adapt,group[i].p);
	printf("當前種群的最優染色體是%d號染色體\n",bestsolution);
}
//選擇
void xuanze()
{
	int i,j,temp;
	double gradient[num];//梯度概率
	double xuanze[num];//選擇染色體的隨機概率
	int xuan[num];//選擇了的染色體
	//初始化梯度概率
	for(i=0;i<num;i++)
	{
		gradient[i]=0.0;
		xuanze[i]=0.0;
	}
	gradient[0]=group[0].p;
	for(i=1;i<num;i++)
	gradient[i]=gradient[i-1]+group[i].p;
	srand((unsigned)time(NULL));
	//隨機產生染色體的存活概率
	for(i=0;i<num;i++)
	{
		xuanze[i]=(rand()%100);
		xuanze[i]/=100;
	}
	//選擇能生存的染色體
	for(i=0;i<num;i++)
	{
		for(j=0;j<num;j++)
		{
			if(xuanze[i]<gradient[j])
			{
				xuan[i]=j; //第i個位置存放第j個染色體
				break;
			}
		}
	}
	//拷貝種群
	for(i=0;i<num;i++)
	{
		grouptemp[i].adapt=group[i].adapt;
		grouptemp[i].p=group[i].p;
		for(j=0;j<cities;j++)
		grouptemp[i].city[j]=group[i].city[j];
	}
	//資料更新
	for(i=0;i<num;i++)
	{
		temp=xuan[i];
		group[i].adapt=grouptemp[temp].adapt;
		group[i].p=grouptemp[temp].p;
		for(j=0;j<cities;j++)
		group[i].city[j]=grouptemp[temp].city[j];
	}
	//用於測試
	/*
	printf("<------------------------------->\n");
	for(i=0;i<num;i++)
	{
		for(j=0;j<cities;j++)
		printf("%4d",group[i].city[j]);
		printf("\n");
		printf("染色體%d的路徑之和與生存概率分別為%4d  %.4f\n",i,group[i].adapt,group[i].p);
	}
	*/
}
//交配,對每個染色體產生交配概率,滿足交配率的染色體進行交配
void  jiaopei()
{
	int i,j,k,kk;
	int t;//參與交配的染色體的個數
	int point1,point2,temp;//交配斷點
	int pointnum;
	int temp1,temp2;
	int map1[cities],map2[cities];
	double jiaopeip[num];//染色體的交配概率
	int jiaopeiflag[num];//染色體的可交配情況
	for(i=0;i<num;i++)//初始化
	jiaopeiflag[i]=0;
	//隨機產生交配概率
	srand((unsigned)time(NULL));
	for(i=0;i<num;i++)
	{
		jiaopeip[i]=(rand()%100);
		jiaopeip[i]/=100;
	}
	//確定可以交配的染色體
	t=0;
	for(i=0;i<num;i++)
	{
		if(jiaopeip[i]<pc)
		{
			jiaopeiflag[i]=1;
			t++;
		}
	}
	t=t/2*2;//t必須為偶數
	//產生t/2個0-9交配斷點
    srand((unsigned)time(NULL));
	temp1=0;
	//temp1號染色體和temp2染色體交配
	for(i=0;i<t/2;i++)
	{
		point1=rand()%cities;
		point2=rand()%cities;
		for(j=temp1;j<num;j++)
		if(jiaopeiflag[j]==1)
		{
			temp1=j;
			break;
		}
		for(j=temp1+1;j<num;j++)
		if(jiaopeiflag[j]==1)
		{
			temp2=j;
			break;
		}
		//進行基因交配
		if(point1>point2) //保證point1<=point2
		{
			temp=point1;
			point1=point2;
			point2=temp;
		}
        memset(map1,-1,sizeof(map1));
		memset(map2,-1,sizeof(map2));
		//斷點之間的基因產生對映
		for(k=point1;k<=point2;k++)
		{
			map1[group[temp1].city[k]]=group[temp2].city[k];
			map2[group[temp2].city[k]]=group[temp1].city[k];
		}
		//斷點兩邊的基因互換
		for(k=0;k<point1;k++)
		{
			temp=group[temp1].city[k];
			group[temp1].city[k]=group[temp2].city[k];
			group[temp2].city[k]=temp;
		}
		for(k=point2+1;k<cities;k++)
		{
			temp=group[temp1].city[k];
			group[temp1].city[k]=group[temp2].city[k];
			group[temp2].city[k]=temp;
		}
		//處理產生的衝突基因
		for(k=0;k<point1;k++)
		{
			for(kk=point1;kk<=point2;kk++)
			if(group[temp1].city[k]==group[temp1].city[kk])
			{
				group[temp1].city[k]=map1[group[temp1].city[k]];
				break;
			}
		}
		for(k=point2+1;k<cities;k++)
		{
			for(kk=point1;kk<=point2;kk++)
			if(group[temp1].city[k]==group[temp1].city[kk])
			{
				group[temp1].city[k]=map1[group[temp1].city[k]];
				break;
			}
		}
		for(k=0;k<point1;k++)
		{
			for(kk=point1;kk<=point2;kk++)
			if(group[temp2].city[k]==group[temp2].city[kk])
			{
				group[temp2].city[k]=map2[group[temp2].city[k]];
				break;
			}
		}
		for(k=point2+1;k<cities;k++)
		{
			for(kk=point1;kk<=point2;kk++)
			if(group[temp2].city[k]==group[temp2].city[kk])
			{
				group[temp2].city[k]=map2[group[temp2].city[k]];
				break;
			}
		}
        temp1=temp2+1;
	}
}
//變異
void bianyi()
{
	int i,j;
	int t;
	int temp1,temp2,point;
	double bianyip[num]; //染色體的變異概率
	int bianyiflag[num];//染色體的變異情況
	for(i=0;i<num;i++)//初始化
	bianyiflag[i]=0;
	//隨機產生變異概率
	srand((unsigned)time(NULL));
	for(i=0;i<num;i++)
	{
		bianyip[i]=(rand()%100);
		bianyip[i]/=100;
	}
	//確定可以變異的染色體
	t=0;
	for(i=0;i<num;i++)
	{
		if(bianyip[i]<pm)
		{
			bianyiflag[i]=1;
			t++;
		}
	}
	//變異操作,即交換染色體的兩個節點
	srand((unsigned)time(NULL));
	for(i=0;i<num;i++)
	{
		if(bianyiflag[i]==1)
		{
	        temp1=rand()%10;
			temp2=rand()%10;
			point=group[i].city[temp1];
            group[i].city[temp1]=group[i].city[temp2];
			group[i].city[temp2]=point;
		}
	}
}
int main()
{
	int i,j,t;
    init();
	groupproduce();
	//初始種群評價
	pingjia();
	t=0;
    while(t++<MAXX)
	{
	     xuanze();
		 //jiaopei();
		 bianyi();
		 pingjia();
	}
	//最終種群的評價
	printf("\n輸出最終的種群評價\n");
	for(i=0;i<num;i++)
	{
		for(j=0;j<cities;j++)
		{
			printf("%4d",group[i].city[j]);
		}
		printf("  adapt:%4d, p:%.4f\n",group[i].adapt,group[i].p);
	}
	printf("最優解為%d號染色體\n",bestsolution);
	return 0;
}


轉載:
http://blog.csdn.net/mylovestart/article/details/8977005

相關文章