Introducción a la inteligencia artificial——Algoritmo genético para resolver el experimento del problema TSP

1. Propósito del experimento:

Familiarizarse y dominar el principio, el proceso y la estrategia de codificación del algoritmo genético, y usar el algoritmo genético para resolver problemas de optimización combinatoria, comprender el proceso de resolución de problemas TSP y probar la influencia de los parámetros principales en los resultados.

2. Principio experimental:

El problema del viajante de comercio, problema TSP (Traveling Salesman Problem) es uno de los problemas más famosos en el campo de las matemáticas. Suponiendo que un hombre de negocios viajero quiere visitar n ciudades, debe elegir el camino que quiere tomar, el límite de la ruta es que cada ciudad solo puede ser visitada una vez, y finalmente debe regresar a la ciudad original de donde partió. El objetivo de la selección de ruta es que la distancia de ruta requerida sea el valor mínimo entre todas las rutas. El problema TSP es un problema de optimización combinatoria. Se puede demostrar que el problema tiene complejidad computacional NPC. Por lo tanto, cualquier método que pueda simplificar la solución de este problema será muy evaluado y se le prestará atención.

El principio básico del algoritmo genético es resolver el problema actuando sobre los genes en el cromosoma para encontrar un buen cromosoma. Necesita evaluar cada cromosoma generado por el algoritmo y seleccionar el cromosoma en función del valor de aptitud, de modo que el el cromosoma con buena adaptabilidad tiene más oportunidades de reproducción En el algoritmo genético se generan aleatoriamente una serie de códigos digitales del problema a resolver, es decir cromosomas, para formar la población inicial, a cada individuo se le da una evaluación numérica a través del fitness y se eliminan los individuos con baja aptitud. Se seleccionan los individuos con alta aptitud para participar en la operación genética, y la colección de individuos después de la operación de herencia forma una nueva población de la próxima generación, y se lleva a cabo la siguiente ronda de evolución. sobre esta nueva población. Este experimento requiere el uso de algoritmos genéticos para resolver el camino más corto del problema TSP.

3. Contenido experimental:

1. Consulte el código central del algoritmo genético dado por el sistema experimental. Se requiere usar el algoritmo genético para resolver diferentes escalas (como 10 ciudades, 30 ciudades y 100 ciudades) bajo el mismo tamaño de población, número máximo de pasos de iteración y número de operaciones independientes Complete los resultados en la Tabla 1 para el problema TSP.

Tabla 1 Los resultados del algoritmo genético para resolver problemas TSP de diferentes escalas

tamaño de la ciudad

tamaño de la poblacion

Número máximo de iteraciones

número de carreras independientes

mejor fitness

peor condición física

condición física promedio

tiempo medio de funcionamiento

10

100

100

10

25.1652

25.8521

25.3501

47 pags

30

100

100

10

10605.7

11868

11281.2

122.8s

100

100

100

10

44334.9

47149.1

46117.6

484.2s

  1. Establezca el tamaño de la población en 100, la probabilidad de cruce en 0,8 y la probabilidad de mutación en 0,8, y luego agregue una estrategia de mutación (como dos puntos adyacentes de intercambio de mutación, mutación inversa o mutación de inserción, etc.) y una asignación de probabilidad de selección individual Se utiliza una estrategia (como la clasificación lineal o la asignación de probabilidades de selección individuales de acuerdo con la clasificación no lineal) para resolver el problema TSP de 30 ciudades (las coordenadas de las 30 ciudades son las siguientes), y los resultados se completan en la Tabla 2.

30 coordenadas de la ciudad:

x[0]=41, x[1]=37,x[2]=54,x[3]=25,x[4]=7,x[5]=2,x[6]=68,x [7]=71,x[8]=54,x[9]=83;

y[0]=94,y[1]=84,y[2]=67,y[3]=62,y[4]=64,y[5]=99,y[6]=58,y[7]=44,y[8]=62,y[9]=69;

x[10]=64,x[11]=18,x[12]=22,x[13]=83,x[14]=91,x[15]=25,x[16]=24,x [17]=58,x[18]=71,x[19]=74;

y[10]=60,y[11]=54,y[12]=60,y[13]=46,y[14]=38,y[15]=38,y[16]=42,y[17]=69,y[18]=71,y[19]=78;

x[20]=87,x[21]=18,x[22]=13,x[23]=82,x[24]=62,x[25]=58,x[26]=45,x [27]=41,x[28]=44,x[29]=4;

y[20]=76,y[21]=40,y[22]=40,y[23]=7,y[24]=32,y[25]=35,y[26]=21,y[27]=26,y[28]=35; y[29]=50;

Tabla 2 Los resultados de la solución de diferentes estrategias de mutación y estrategias de asignación de probabilidad de selección individual

estrategia de mutación

asignación de probabilidad de elección individual

Número máximo de iteraciones

número de carreras independientes

mejor fitness

peor condición física

condición física promedio

tiempo medio de funcionamiento

intercambio de dos puntos

Distribución proporcional según fitness

100

10

889.434

982.154

938.503

59s

intercambio de dos puntos

Ordenar linealmente

100

10

488.833

567.304

513.735

51 años

Intercambiar dos puntos adyacentes

Ordenar linealmente

100

10

1022.77

1104.54

1064.78

49,1 s

Intercambiar dos puntos adyacentes

Distribución proporcional según fitness

100

10

878.549

969.802

939.414

58s

3. Dados los datos de 34 capitales de provincia en China, se requiere diseñar un algoritmo genético mejorado basado en estos datos para resolver el problema TSP. Se requiere proporcionar 1) la estrategia del algoritmo mejorado y el código central, 2) la configuración de los parámetros principales del algoritmo mejorado (tamaño de la población, probabilidad de cruce, probabilidad de mutación, número máximo de pasos de iteración, etc.), 3) la distancia más corta entre las 34 capitales de provincia finalmente obtenidas por el algoritmo mejorado Valor de la ruta, tiempo óptimo individual y de ejecución del algoritmo, 4) Dada la misma configuración de parámetros (tamaño de la población, probabilidad de cruce, probabilidad de mutación, número máximo de pasos de iteración, etc.), usando el algoritmo genético básico (sin usar la estrategia mejorada) para obtener el valor de la ruta más corta, el tiempo óptimo de ejecución individual y del algoritmo de las 34 capitales de provincia.

Figura 1 Ubicación de 34 capitales de provincia en China (1295.72)

Tabla 3 34 ciudades capitales de provincia y tabla de coordenadas de píxeles

Ciudad

Tíbet

yunnan

sichuan

qinghai

Ningxia

Gansu

Mongolia interior

Heilongjiang

Jilin

liaoning

Beijing

Tianjín

numero de ciudad

1

2

3

4

5

6

7

8

9

10

11

12

coordenada x

100

187

201

187

221

202

258

352

346

336

290

297

coordenada Y

211

265

214

158

142

165

121

66

85

106

127

135

Ciudad

Hebei

Shandong

Henán

Shanxi

Shanxi

Anhui

Jiangsu

Llevar a la fuerza

Zhejiang

Jiangxi

Hubei

Hunán

numero de ciudad

13

14

15

dieciséis

17

18

19

20

21

22

23

24

coordenada x

278

296

274

265

239

302

316

334

325

293

280

271

coordenada Y

147

158

177

148

182

203

199

206

215

233

216

238

Ciudad

Guizhou

Guangxi

Guangdong

fujián

Hainan

Macao

Hong Kong

Taiwán

Chongqing

Xinjiang

numero de ciudad

25

26

27

28

29

30

31

32

33

34

coordenada x

221

233

275

322

250

277

286

342

220

104

coordenada Y

253

287

285

254

315

293

290

263

226

77

x[0]=100, x[1]=187,x[2]=201,x[3]=187,x[4]=221,x[5]=202,x[6]=258,x [7]=352,x[8]=346,x[9]=336;

y[0]=211,y[1]=265,y[2]=214,y[3]=158,y[4]=142,y[5]=165,y[6]=121,y[7]=66,y[8]=85,y[9]=106;

x[10]=290,x[11]=297,x[12]=278,x[13]=296,x[14]=274,x[15]=265,x[16]=239,x [17]=302,x[18]=316,x[19]=334;

y[10]=127,y[11]=135,y[12]=147,y[13]=158,y[14]=177,y[15]=148,y[16]=182,y[17]=203,y[18]=199,y[19]=206;

x[20]=325,x[21]=293,x[22]=280,x[23]=271,x[24]=221,x[25]=233,x[26]=275,x [27]=322,x[28]=250,x[29]=277;

y[20]=215,y[21]=233,y[22]=216,y[23]=238,y[24]=253,y[25]=287,y[26]=285,y[27]=254,y[28]=315; y[29]=293;

x[30]=286, x[31]=342,x[32]=220,x[33]=104;

y[30]=290,y[31]=263,y[32]=226,y[33]=77;

3.1 Resultados:

3.1.1 Aquí hay dos resultados experimentales, la diferencia es que solo el punto de partida inicial es diferente

① Dibuje el camino como se muestra en la Figura 2 (basado en Python, punto de partida 15):

Fig. 2 Gráfico que muestra la solución óptima

Longitud de ruta más corta 1532.3994414550848

Representación de ruta: [23, 32, 24, 1, 2, 0, 33, 3, 5, 4, 12, 14, 16, 22, 21, 27, 31, 30, 26, 29, 28, 25, 20, 19, 18, 17, 13, 11, 9, 8, 7, 10, 6]

La longitud de la ruta disminuye con el número de iteraciones:

Figura 3 La relación entre el número de iteraciones y la solución óptima

② Dibuje el camino como se muestra en la figura (basado en python, punto de partida 32):

La figura 4 es un gráfico que muestra la solución óptima.

Longitud de ruta más corta: 1551.0699954694958

Representación de ruta: [1, 28, 25, 24, 18, 20, 19, 31, 27, 29, 30, 26, 23, 21, 22, 16, 14, 17, 13, 9, 8, 7, 11, 10, 12, 15, 6, 4, 5, 0, 33, 3, 2]

La longitud de la ruta disminuye con el número de iteraciones:

Figura 5 La relación entre la solución óptima y el número de iteraciones

3.1.2

Si no se mejora, use el programa original y los parámetros se establecen de la siguiente manera (basado en C++):

Longitud del cromosoma: 34

Pasos máximos de iteración: 500

Tamaño de la población: 100

Probabilidad de cruce: 0.5

Probabilidad de mutación 0.15

Operación de selección: distribuya la probabilidad de selección de individuos de acuerdo con la relación de aptitud y seleccione individuos por medio de la ruleta

Operación de cruce: cruce PMX

Operación de mutación: intercambiar dos puntos adyacentes

El resultado se muestra en la Figura 6:

Figura 6 Resultados

La longitud de ruta óptima es: 6246.62

Ruta: 32-20-18-21-28-29-26-24-13-30-12-10-31-33-2-3-1-7-9-4-15-11-0-5- 8-6-17-16-23-25-19-22-27-14

El tiempo de ejecución es: 214.6s

Se puede ver que el algoritmo mejorado es bastante efectivo.

3.2 Estrategia de algoritmo mejorada y código central :

①Configuración de parámetros:
#número de población

cuenta=300

#mejorar tiempos

mejorar_cuenta=10000

#Tiempos de evolución

itter_time=3000

#Establezca la probabilidad de definición de los fuertes, es decir, el 30% superior de la población son los fuertes

retención_tasa=0.3

#Establecer la probabilidad de supervivencia de los débiles

random_select_rate=0.5

#tasa de mutación

tasa_mutación=0.1

②Codificación de ruta:

Numerar las ciudades 0, 1, 2, 3...33, cromosoma {x1, x2, x3...x33}, lo que significa empezar desde x1, pasar por x2, x3....x33 y luego volver a x1, el punto de partida se puede establecer arbitrariamente, en este programa se establece en 15.

③ Inicializar la población:

Para acelerar la velocidad de ejecución del programa, se deben seleccionar algunos individuos mejores en la selección de la población inicial. Primero use el algoritmo de aproximación clásico: algoritmo de círculo mejorado para obtener una mejor población inicial. La idea del algoritmo es generar aleatoriamente un cromosoma, como {1, 2, ... 33}, intercambiar las posiciones secuenciales de las dos ciudades arbitrariamente, si la distancia total disminuye, actualizar y cambiar el cromosoma, y repita hasta que no se puedan realizar más modificaciones.

código:

#Inicializar población

población = []

para i en rango (recuento):

    # Generar individuos aleatoriamente

    x = índice.copia()

    aleatorio.shuffle(x)

    mejorar(x)

    población.append(x)

# mejora

def mejorar(x):

    yo=0

    distancia=obtener_distancia_total(x)

    mientras i<mejorar_cuenta:

        # aleatorio [a,b]

        u=aleatorio.randint(0,len(x)-1)

        v = random.randint(0, len(x)-1)

        si tu!=v:

            new_x=x.copiar()

            t=nuevo_x[u]

            nuevo_x[u]=nuevo_x[v]

            nuevo_x[v]=t

            nueva_distancia=obtener_distancia_total(nueva_x)

            si nueva_distancia<distancia:

                distancia=nueva_distancia

                x=nuevo_x.copiar()

        demás:

            continuar

        i+=1

④Seleccionar estrategia:

Aunque el método de la rueda de la ruleta es la estrategia de selección más utilizada, esta estrategia puede producir grandes errores de muestreo, por lo que utiliza la selección natural para calcular la distancia entre cada ciudad y almacenarla en la matriz.La distancia total Ordenar de menor a mayor, seleccionar los cromosomas con gran adaptabilidad, y luego seleccionar los cromosomas con menos adaptabilidad pero los cromosomas supervivientes (selección aleatoria).

Código central:

# seleccion natural

def selección(población):

    # Ordenar la distancia total de menor a mayor

    calificado = [[get_total_distance(x), x] para x en la población]

    calificado = [x[1] para x en ordenado(calificado)]

    # Seleccionar los cromosomas más adaptativos

    retener_longitud = int(len(calificado) * retener_tasa)

    padres = calificado[:retain_length]

    # Seleccionar cromosomas menos adaptativos pero sobrevivientes

    para el cromosoma en graded[retain_length:]:

        si random.random() < random_select_rate:

            padres.append(cromosoma)

    padres de familia

⑤ Estrategia de variación:

De acuerdo con la tasa de mutación dada, seleccione al azar tres números enteros para los individuos mutados seleccionados, que satisfagan 1<u<v<w<33, e inserte el segmento genético entre v y u (incluidos u y v) en w más tarde. Reemplace la mutación original de intercambio de dos puntos adyacentes y la estrategia de mutación de intercambio de dos puntos. 

Código central:

#mutaciones

mutación def (hijos):

    for i in range(len(niños)):

        si random.random() < tasa_mutación:

            hijo=hijos[i]

            u=aleatorio.randint(1,len(hijo)-4)

            v = random.randint(u+1, len(niño)-3)

            w= aleatorio.randint(v+1, len(niño)-2)

            hijo=hijos[i]

            niño=niño[0:u]+niño[v:w]+niño[u:v]+niño[w:]

4. Envíe el informe del experimento y el programa fuente.

3. Resultados experimentales :

Resultado del contenido experimental 1:

Tabla 1 Los resultados del algoritmo genético para resolver problemas TSP de diferentes escalas

tamaño de la ciudad

tamaño de la poblacion

Número máximo de iteraciones

número de carreras independientes

mejor fitness

peor condición física

condición física promedio

tiempo medio de funcionamiento

10

100

100

10

25.1652

25.8521

25.3501

47 pags

30

100

100

10

10605.7

11868

11281.2

122.8s

100

100

100

10

44334.9

47149.1

46117.6

484.2s

Contenido experimental 2 resultados:

Tabla 2 Los resultados de la solución de diferentes estrategias de mutación y estrategias de asignación de probabilidad de selección individual

estrategia de mutación

asignación de probabilidad de elección individual

Número máximo de iteraciones

número de carreras independientes

mejor fitness

peor condición física

condición física promedio

tiempo medio de funcionamiento

intercambio de dos puntos

Distribución proporcional según fitness

100

10

889.434

982.154

938.503

59s

intercambio de dos puntos

Ordenar linealmente

100

10

488.833

567.304

513.735

51 años

Intercambiar dos puntos adyacentes

Ordenar linealmente

100

10

1022.77

1104.54

1064.78

49,1 s

Intercambiar dos puntos adyacentes

Distribución proporcional según fitness

100

10

878.549

969.802

939.414

58s

El resultado del contenido del experimento 3, ubicado en el contenido del experimento 3:

La ruta se muestra en la Figura 2:

Longitud de ruta más corta 1532.3994414550848

Representación de ruta: [23, 32, 24, 1, 2, 0, 33, 3, 5, 4, 12, 14, 16, 22, 21, 27, 31, 30, 26, 29, 28, 25, 20, 19, 18, 17, 13, 11, 9, 8, 7, 10, 6]

4. Pensamiento experimental y experiencia :

  1. Analizar el rendimiento del algoritmo del algoritmo genético para resolver problemas TSP de diferentes escalas.

Cuanto mayor sea el tamaño de la ciudad, mayor será el número de iteraciones, más larga será la búsqueda de la solución óptima y mayor será el tiempo de espera para el resultado.

2. Agregue 1 estrategia de mutación y 1 estrategia de distribución de probabilidad de selección individual, y compare la influencia de diferentes estrategias de mutación y estrategias de distribución de selección individual en los resultados del algoritmo al resolver problemas de TSP en 30 ciudades.

Se agregó mutación de dos puntos adyacentes y clasificación lineal para seleccionar individuos:

Estrategia de mutación:

void change1(vector<int>& K, int N){//estrategia de mutación: mutación de intercambio entre dos puntos adyacentes

int i = next_int() % N;

intercambiar(K[i], K[(i + 1) % N]);

}

Estrategia de selección individual:

if(make_p==1)//clasificación lineal

    {

        for(int i=0;i<popsize;i++)

ps[i]=(200-2*i)/tamaño pop*(tamaño pop+1);

}

A partir de los resultados experimentales, la clasificación lineal es mejor y la estrategia de intercambio aleatorio de dos puntos es obviamente mejor que la estrategia de intercambio de dos puntos adyacentes.

3. Analizar comparativamente la influencia de la estrategia mejorada del algoritmo genético en los resultados de la resolución de los problemas TSP de 34 ciudades.

La razón principal es que se ha realizado una mejora relativamente grande en la selección del valor de aptitud. Los mejores individuos se seleccionan primero y algunos individuos pobres se seleccionan aleatoriamente. Al mejorar el código de algunos parámetros, la selección y la mutación, puede hacer lo que quiere obtener La solución óptima de es mejor Si no se utiliza la mejora, la solución óptima que se puede obtener en la operación final es de aproximadamente 7,8 mil, como se muestra en la Figura 7, y la precisión está lejos de ser suficiente.

 

Figura 7 Resultados de carrera no mejorados

4. Resume la experiencia del experimento:

Hay muchas otras estrategias de mejora, tales como:

①Usando el algoritmo codicioso para inicializar la población, la idea básica de cada generación individual es: primero seleccione al azar la ciudad actual de n ciudades como el primer gen, y luego encuentre la ciudad csiguiente (csiguiente) de las n-1 ciudades restantes cnext es la ciudad más cercana a ccurrent) como el segundo gen, y luego encuentra la ciudad cnext+1 de las n-2 ciudades restantes (cnext+1 es la ciudad más cercana a cnext) como el tercer gen, y así sucesivamente hasta Traverse n ciudades hasta ahora. La proporción de algunas poblaciones generadas por el algoritmo codicioso no es grande. Si bien mejora la calidad general de la población inicial, no afectará la diversidad de la población inicial, lo que ayuda a acelerar la velocidad de optimización. Debido a que no estoy muy familiarizado con el código, no pude cambiarlo a un algoritmo codicioso para inicializar la población.

② También es posible ampliar adecuadamente la aptitud y considerar la parte fraccionaria, pero a partir de los resultados de la ejecución experimental, no es muy significativo. La solución óptima es relativamente promedio y la distancia aún es bastante grande.

③Operador de cruce mejorado: el operador de cruce de dos puntos comúnmente utilizado en algoritmos genéticos básicos. Este método de cruce solo cruza los genes entre los dos puntos del individuo progenitor. Los genes fuera de los dos puntos no cambian o son ciegos debido a la duplicación de nodos. El los buenos genes de los padres no se pueden heredar efectivamente. Se puede utilizar un cruce aleatorio de tres segmentos de dos puntos.

Código fuente no mejorado:

#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<time.h>
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
#define PB push_back
#define MP make_pair

int next_int()
{
	return rand()*(RAND_MAX+1)+rand();
}
double next_double()
{
	return (double(rand()*(RAND_MAX+1)+rand()))/((RAND_MAX+1)*RAND_MAX+RAND_MAX);
}
void pmx(VI& a,VI& b,int pointcnt)//PMX交叉
{
	int sa=next_int()%pointcnt,sb=next_int()%pointcnt;//随机选择两交叉位
	int temp;
	if (sa>sb)
	{
		temp=sa;
		sa=sb;
		sb=temp;
	}//保证交叉位sa<=sb
	VI aa(pointcnt),bb(pointcnt);
	int i;	
	for(i=0;i<pointcnt;i++)
	{
		aa[i]=a[i],bb[i]=b[i];	
	}
	VI m1(pointcnt,-1);
	VI m2(pointcnt,-1);	
	VI v1tov2(pointcnt,-1);
	for(i=sa;i<=sb;i++)
	{   
		m1[aa[i]]=-2;	//m1存放aa非交叉段可代换的基因
		m2[bb[i]]=-2;	//m2存放aa非交叉段可代换的基因
	}	
	for(i=0;i<pointcnt;i++)	{   
		
		if(m2[i]==m1[i])//去掉m1和m2中重复代换的基因
		{
			m2[i]=-1;
			m1[i]=-1;
		}
	}
	int aaa=0;
	for(i=sa;i<=sb;i++)
	{
		if ((m1[aa[i]]==-2)&&(m2[bb[i]]==-2))
		{
			v1tov2[aa[i]]=bb[i];//v1tov2存放首先可以确定的互换基因
			m1[aa[i]]=-1;
			m2[bb[i]]=-1;
			aaa++;			
		}
	}
	if(aaa!=(sb-sa+1))
	{
		for(i=0;i<pointcnt;i++)	
			if (m1[i]==-2) 
			{
				int aflag=0;
				for(int j=0;j<pointcnt;j++)	
					if( (m2[j]==-2) && (aflag==0))//寻找并确定可以互换的基因
					{
						v1tov2[i]=j; 
						aflag=1;
						aaa++;
						m2[j]=-1;
						m1[i]=-1;					
					}
			}

	}
	for(i=sa;i<=sb;i++)	{	
	
		swap(aa[i],bb[i]);	//交换sa到sb之间的基因串
	}

	for(i=0;i<pointcnt;i++)//查找染色体aa中sa之前和sb之后的基因是否有重复
	{   
		if ((i<sa)||(i>sb))
			for (int j=sa;j<=sb;j++)
			{
				if(aa[i]==aa[j])  //有重复基因
				{  
					for(int k=0;k<pointcnt;k++)
						if(aa[i]==v1tov2[k])  
							aa[i]=k;	//进行互换			
				
				}
			}
		
	}
		
	for(i=0;i<pointcnt;i++)//查找染色体bb中sa之前和sb之后的基因是否有重复
	{  
		if ((i<sa)||(i>sb))
			for (int j=sa;j<=sb;j++)
			{	
				if(bb[i]==bb[j]) //有重复基因			
					bb[i]=v1tov2[bb[i]];	//进行互换				
			}
	
	}
	a=aa;
	b=bb;
	
}

vector<double> x,y;
double fitness(const VI& v,int pointcnt)//计算适应度
{
	double r=0;
	for(int i=0;i<pointcnt;i++)
	{
		double dx=x[v[i]]-x[v[(i+1)%pointcnt]];
		double dy=y[v[i]]-y[v[(i+1)%pointcnt]];
		r+=sqrt(dx*dx+dy*dy);//个体的适应度为相邻两城市之间的距离平方的平方根和
	}
	return 1.0/r;
}
void change0(vector<int>& K,int N)//变异策略:两点互换
{
	int i=next_int()%N;
	int d=next_int()%(N-1);
	int j=(i+1+d)%N;
	swap(K[i],K[j]);
}


void change1(vector<int>& K, int N){//变异策略:相邻两点互换变异 
	int i = next_int() % N;
	swap(K[i], K[(i + 1) % N]);	
}



void mutate(VI& route,int mutate_type,int pointcnt)
{
	
	if(mutate_type==0)//两点互换
		change0(route,pointcnt);	
	if(mutate_type==1)//相邻两点互换变异 
	    change1(route,pointcnt);
}



bool pair_dec(const pair<double,VI*>& a,const pair<double,VI*>& b)
{
	return a>b;
}

class other_population
{
public:
	int popsize,pointcnt;//种群规模,染色体长度
	double pc,pm;//交叉概率,变异概率
	vector<pair<double,VI*> >pop;//种群
	pair<double,VI*> bestofpop;//最好个体
	int cross_type;//交叉类型
	int mutate_type;//变异类型
	int make_p;//个体概率分配策略类型
	int select_type;//个体选择类型
	int toursize;//竞赛规模
	double bestp;//最好个体选择概率
	other_population(int a,int b,int c,int f,int g,double d,double e,int h,double j,int m)
	{
		popsize=a,pointcnt=b,cross_type=c,mutate_type=f,make_p=g,pc=d,pm=e,toursize=h,bestp=j,select_type=m;
		for(int i=0;i<popsize;i++)//初始化种群
		{
			VI* v=new VI(pointcnt);
			for(int j=0;j<pointcnt;j++)
				(*v)[j]=j;
			random_shuffle(v->begin(),v->end());
			pop.PB(MP(fitness(*v,pointcnt),v));
		}
		sort(pop.begin(),pop.end(),pair_dec);
		bestofpop.first=pop[0].first;//初始时最好个体的适应度
		bestofpop.second=new VI(*pop[0].second);//初始时最好个体的染色体
	}
	~other_population()
	{
		for(int i=0;unsigned(i)<pop.size();i++)
			delete pop[i].second;
		delete bestofpop.second;
	}
	void next()//产生下一代种群
	{
		vector<double> ps(popsize);
		if(make_p==0) //按适应度比例分配个体的选择概率
		{
			double sum=0;
			for(int i=0;i<popsize;i++)
				sum+=pop[i].first;//计算种群的适应度和
			for(int i=0;i<popsize;i++)
				ps[i]=pop[i].first/sum;
		}	
		
		
		if(make_p==1)//线性排序 
	    {
	        for(int i=0;i<popsize;i++)
			ps[i]=(200-2*i)/popsize*(popsize+1);	
		}
	
		if(select_type==0)//轮盘赌选择个体
		{
			vector<pair<double,VI*> > select_res;
			vector<double> addsum(popsize);
			for(int i=0;i<popsize-1;i++)//计算个体的累计概率
			{
				if(i==0)
					addsum[i]=ps[0];
				else
					addsum[i]=addsum[i-1]+ps[i];
			}
			addsum[popsize-1]=1;//1.5;
			for(int i=0;i<popsize;i++)
			{
				double rd=next_double();
				int r=lower_bound(addsum.begin(),addsum.end(),rd)-addsum.begin();
				VI* v=new VI(*pop[r].second);
				select_res.PB(MP(fitness(*v,pointcnt),v));
			}
			for(int i=0;i<popsize;i++)
				delete pop[i].second;
			pop=select_res;
		}		
		for(int cc=0;cc<popsize/2;cc++)//随机选择两个个体,然后进行交叉
		{
			int a=next_int()%popsize;
			int b=(a+1+(next_int()%(popsize-1)))%popsize;
			if(next_double()<pc)//随机数小于交叉概率,进行交叉
			{
				if(cross_type==0)//pmx交叉
					pmx(*pop[a].second,*pop[b].second,pointcnt);
			
				pop[a].first=fitness(*pop[a].second,pointcnt);//计算交叉后个体a的适应度
				if(bestofpop.first<pop[a].first)//更新最好个体
				{
					bestofpop.first=pop[a].first;
					delete bestofpop.second;
					bestofpop.second=new VI(*pop[a].second);
				}
				pop[b].first=fitness(*pop[b].second,pointcnt);//计算交叉后个体b的适应度
				if(bestofpop.first<pop[b].first)//更新最好个体
				{
					bestofpop.first=pop[b].first;
					delete bestofpop.second;
					bestofpop.second=new VI(*pop[b].second);
				}
			}
		}
		for(int i=pop.size()-1;i>=0;i--)//进行变异
			if(next_double()<pm)//随机数小于变异概率,进行变异
			{
				mutate(*pop[i].second,mutate_type,pointcnt);//变异
				pop[i].first=fitness(*pop[i].second,pointcnt);//计算变异后个体的适应度
			}
		sort(pop.begin(),pop.end(),pair_dec);//从大到小排序
		if(bestofpop.first<pop[0].first)//更新最好个体
		{
			delete bestofpop.second;
			bestofpop.first=pop[0].first;
			bestofpop.second=new VI(*pop[0].second);
		}
	}
};

int main()
{
	srand((unsigned)time(NULL));
	int CASNUM,POINTCNT,POPSIZE,GENERATIONS;
	//scanf("%d",&CASNUM);//输入实验次数
	CASNUM=10;//输入实验次数
	cout << "实验次数:" << CASNUM << "次" << endl;
	//scanf("%d%d%d",&POINTCNT,&POPSIZE,&GENERATIONS);//输入染色体长度(城市数),种群规模,最大迭代步数
	POINTCNT=30;//输入染色体长度(城市数)
	POPSIZE=100,GENERATIONS=100;//输入种群规模,最大迭代步数
	x.resize(POINTCNT);
	y.resize(POINTCNT);
//	x[0]=0, x[1]=1.1,x[2]=3.5,x[3]=3,x[4]=7,x[5]=8,x[6]=4,x[7]=4.5,x[8]=9,x[9]=2;
	//x[10]=10, x[11]=11.1,x[12]=13.5,x[13]=13,x[14]=17,x[15]=18,x[16]=14,x[17]=14.5,x[18]=19,x[19]=12;
//	y[0]=1.1,y[1]=3,y[2]=2,y[3]=4,y[4]=5.1,y[5]=8,y[6]=4,y[7]=4.5,y[8]=9,y[9]=2;
	//y[10]=11.1,y[11]=13,y[12]=12,y[13]=14,y[14]=15.1,y[15]=18,y[16]=14,y[17]=14.5,y[18]=19,y[19]=12;
	
x[0]=41, x[1]=37,x[2]=54,x[3]=25,x[4]=7,x[5]=2,x[6]=68,x[7]=71,x[8]=54,x[9]=83;
y[0]=94,y[1]=84,y[2]=67,y[3]=62,y[4]=64,y[5]=99,y[6]=58,y[7]=44,y[8]=62,y[9]=69;
x[10]=64,x[11]=18,x[12]=22,x[13]=83,x[14]=91,x[15]=25,x[16]=24,x[17]=58,x[18]=71,x[19]=74;
y[10]=60,y[11]=54,y[12]=60,y[13]=46,y[14]=38,y[15]=38,y[16]=42,y[17]=69,y[18]=71,y[19]=78;
x[20]=87,x[21]=18,x[22]=13,x[23]=82,x[24]=62,x[25]=58,x[26]=45,x[27]=41,x[28]=44, x[29]=4;
y[20]=76,y[21]=40,y[22]=40,y[23]=7,y[24]=32,y[25]=35,y[26]=21,y[27]=26,y[28]=35; y[29]=50;

	
	cout<<"城市数="<<POINTCNT<<endl;
	cout<<"各城市坐标:"<<endl;
	//srand((unsigned)time(NULL));
/*	for(int i=10;i<POINTCNT;i++)
	{
		x[i]=next_int()%1000;y[i]=next_int()%1000;
	}*/
	for(int i=0;i<POINTCNT;i++)
	{
		//scanf("%lf%lf",&x[i],&y[i]);//输入各个城市的坐标		
		cout<<"["<<x[i]<<", "<<y[i]<<"]"<<endl;//输出各个城市的坐标				
	}
	cout<<"染色体长度:"<<POINTCNT<<endl;
	cout<<"最大迭代步数:"<<GENERATIONS<<endl;
	cout<<"种群规模:"<<POPSIZE<<endl;
	int select_type,make_p_type,k,cross_type,mutate_type;
	double q,pc,pm;
	
	select_type=0,make_p_type=1,k=5;//输入个体选择方法类型,个体选择概率分配类型,竞赛规模
	q=0.5,pc=0.8,pm=0.8;//输入最好个体选择概率,交叉概率,变异概率
	cross_type=0,mutate_type=0;//输入交叉类型,变异类型
	
	
	cout<<"交叉概率:"<<pc<<endl;
	cout<<"变异概率"<<pm<<endl;
	cout<<"选择操作:按适应度比例分配个体的选择概率,轮盘赌选择个体"<<endl;
	cout<<"交叉操作:PMX交叉"<<endl;
	cout<<"变异操作:两点互换"<<endl;
	double best=1e9,worst=0,sum=0;
	VI res;
	clock_t start_time;
	start_time=clock();
	cout << endl;
	cout << "正在计算中......" << endl;
	for(int cas=0;cas<CASNUM;cas++)//
	{
		other_population gen(POPSIZE,POINTCNT,cross_type,mutate_type,make_p_type,pc,pm,k,q,select_type);
	
		for(int g=0;g<GENERATIONS;g++)//进行迭代进化
			gen.next();
		if(best>1.0/gen.bestofpop.first)//更新最好适应度
		{
			best=1.0/gen.bestofpop.first;
			res=*gen.bestofpop.second;//存放最好个体的染色体
		}
		if(worst<1.0/gen.bestofpop.first)//更新最差适应度
			worst=1.0/gen.bestofpop.first;
		sum+=1.0/gen.bestofpop.first;//计算各次最好个体的适应度之和
	}
	cout << endl; 
	cout << CASNUM << "次遗传算法求解的结果如下:" << endl;
	clock_t	end_time=clock();
	double durTime=double(end_time-start_time);	
	sum/=CASNUM;//计算平均适应度
	cout<<"最好适应度:"<<best<<"\n"<<"最差适应度:"<<worst<<"\n"<<"平均适应度:"<<sum<<"\n";
	cout<<"输出最好解:";
	for(int i=0;i<POINTCNT;i++)//输出解
	{
		cout<<res[i];//输出各城市
		if (i<POINTCNT-1)
			cout<<"-";
	}
	cout<<endl;
	cout<<"平均运行时间:"<<durTime/CASNUM<<"s"<<endl;
	cout<<endl;

	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/cangzhexingxing/article/details/124015579
Recomendado
Clasificación