第28題
(TSP 問(wèn)題的交叉算子) TSP 問(wèn)題 (Traveling Salesman Problem) 描述如下: 給定 n 個(gè)城市,
構(gòu)成一個(gè)完全圖,任何兩城市之間都有一個(gè)代價(jià)(例如路程、旅費(fèi)等) ,現(xiàn)要構(gòu)造遍歷所有
城市的環(huán)路,每個(gè)城市恰好經(jīng)過(guò)一次,求使總代價(jià)達(dá)到最小的一條環(huán)路。
遺傳算法是求解該問(wèn)題的一個(gè)很有效的近似算法。 在該算法中, 一個(gè)個(gè)體為一條環(huán)路, 其編
碼方法之一是 1 到 n 這 n 個(gè)數(shù)字的一個(gè)排列, 每個(gè)數(shù)字為一個(gè)城市的編號(hào)。 例如當(dāng) n=5 時(shí),
“ 3 4 2 1 5 表示該方案實(shí)施的路線為 ” 3->4->2->1->5->3 。遺傳算法的核心是通過(guò)兩個(gè)個(gè)體的
交叉操作,產(chǎn)生兩個(gè)新的個(gè)體。下面的程序給出了最簡(jiǎn)單的一種交叉算法。
具體過(guò)程如下:
(1)選定中間一段作為互換段,該段的起止下標(biāo)為 t1,t2,隨機(jī)生成 t1,t2 后,互換兩段。
(2)互換后,在每個(gè)新的排列中可能有重復(fù)數(shù)字,因而不能作為新個(gè)體的編碼,一般再做兩
步處理:
(2.1) 將兩個(gè)互換段中,共同的數(shù)字標(biāo)記為 0,表示已處理完。
(2.2) 將兩個(gè)互換段中其余數(shù)字標(biāo)記為 1,按順序?qū)⒒Q段外重復(fù)的數(shù)字進(jìn)行替換。
例如: n=12,兩個(gè)個(gè)體分別是:
a1: 1 3 5 4 * 2 6 7 9 * 10 12 8 11
a2: 3 2 1 12 * 6 7 10 11 * 8 5 4 9
t1=5,t2=8。
上述每一行中,兩個(gè)星號(hào)間的部分為互換段。假定數(shù)組的下標(biāo)從 1 開(kāi)始,互換
后有:
a1: 1 3 5 4 * 6 7 10 11 * 10 12 8 11
a2: 3 2 1 12 * 2 6 7 9 * 8 5 4 9
然后,將數(shù)字 6,7 對(duì)應(yīng)的項(xiàng)標(biāo)記為 0,星號(hào)內(nèi)數(shù)字 2,9,10,11 對(duì)應(yīng)的項(xiàng)標(biāo)記為 1,并且按順序
對(duì)應(yīng)關(guān)系為 : 10<->2 ,11<->9。于是,將 a1[9]=10 替換為 a1[9]=2 ,將 a2[2]=2 替換為 a2[2]=10 ,
類(lèi)似再做第 2 組替換。這樣處理后,就得到了兩個(gè)新個(gè)體:
a1: 1 3 5 4 6 7 10 11 2 12 8 9
a2: 3 10 1 12 2 6 7 9 8 5 4 11
(3)輸出兩個(gè)新個(gè)體的編碼。
程序:
#include <stdio.h>
#include <stdlib.h>
#define N 20
int a1[N],a2[N],kz1[N],kz2[N],n;
int rand1(int k)
{
int t=0;
while(t<2|| t>k)
t=(int)((double)rand()/RAND_MAX*k);
return t;
}
void read1(int a[],int m)
{ 讀入數(shù)組元素 a[1]至 a[m], a[0]=0 ,略. }
void wrt1(int a[],int m)
{ 輸出數(shù)組元素 a[1]至 a[m],略. }
void cross(int a1[], int a2[],int t1, int t2, int n)
{
int i,j,k,t,kj;
for(i=t1; i<=t2; i++)
{
t=a1[i]; ①;
}
for(i=1;i<=n;i++)
if(i<t1 || i>t2)
kz1[i]=kz2[i]=-1;
else
②;
for(i=t1;i<=t2;i++)
for(j=t1;j<=t2;j++)
if(a1[i]==a2[j])
{
③ ; break;
}
for(i=t1;i<=t2;i++)
if(kz1[i]==1)
{
for(j=t1;j<=t2;j++)
if(kz2[j]==1)
{
kj=j; break;
}
for(j=1;j<=n;j++)
if( ④ )
{
a1[j]=a2[kj];break;
}
for(j=1;j<=n;j++)
if( ⑤ )
{
a2[j]=a1[i]; break;
}
kz1[i]=kz2[kj]=0;
}
}
int main()
{
int k,t1,t2;
printf("input (n>5):\n"); scanf("%d",&n);
printf("input array 1 (%d'numbers):\n",n); read1(a1,n);
printf("input array 2 (%d'numbers):\n",n); read1(a2,n);
t1=rand1(n-1);
do
{
t2=rand1(n-1);
}while(t1==t2);
if(t1>t2)
{
k=t1; t1=t2; t2=k;
}
⑥
wrt1(a1,n); wrt1(a2,n);
}