Эвристические алгоритмы
Презентация Лекция 11
Муравьиный алгоритм
Применение к задачи коммивояжера
import random
import math
import matplotlib.pyplot as plt
# -------------------------------
NUM_CITIES = 20
NUM_ANTS = 50
ALPHA = 1.0 # Влияние феромона
BETA = 5.0 # Влияние расстояния
EVAPORATION = 0.5 # Коэффициент испарения
Q = 100 # Интенсивность феромона
GENERATIONS = 100
# -------------------------------
# Генерация случайных координат городов
cities = [(random.uniform(0, 100), random.uniform(0, 100)) for _ in range(NUM_CITIES)]
# Расстояния между городами
distance_matrix = [[math.hypot(x1 - x2, y1 - y2) for x2, y2 in cities] for x1, y1 in cities]
# Начальные феромоны
pheromone = [[1.0 for _ in range(NUM_CITIES)] for _ in range(NUM_CITIES)]
# Выбор следующего города по вероятностной формуле
def select_next_city(ant_path, current_city):
probabilities = []
for city in range(NUM_CITIES):
if city in ant_path:
probabilities.append(0)
else:
tau = pheromone[current_city][city] ** ALPHA
eta = (1 / distance_matrix[current_city][city]) ** BETA
probabilities.append(tau * eta)
total = sum(probabilities)
if total == 0:
return random.choice([c for c in range(NUM_CITIES) if c not in ant_path])
probabilities = [p / total for p in probabilities]
return random.choices(range(NUM_CITIES), weights=probabilities)[0]
# Основной цикл
best_path = None
best_length = float('inf')
for gen in range(GENERATIONS):
all_paths = []
all_lengths = []
for _ in range(NUM_ANTS):
path = [random.randint(0, NUM_CITIES - 1)]
while len(path) < NUM_CITIES:
path.append(select_next_city(path, path[-1]))
path_length = sum(distance_matrix[path[i]][path[(i+1)%NUM_CITIES]] for i in range(NUM_CITIES))
all_paths.append(path)
all_lengths.append(path_length)
if path_length < best_length:
best_length = path_length
best_path = path
# Испарение феромона
for i in range(NUM_CITIES):
for j in range(NUM_CITIES):
pheromone[i][j] *= (1 - EVAPORATION)
# Обновление феромона
for path, length in zip(all_paths, all_lengths):
for i in range(NUM_CITIES):
a, b = path[i], path[(i + 1) % NUM_CITIES]
pheromone[a][b] += Q / length
pheromone[b][a] += Q / length
print(f"Generation {gen}: shortest path = {best_length:.2f}")
# Визуализация лучшего маршрута
def plot_route(route):
x = [cities[i][0] for i in route] + [cities[route[0]][0]]
y = [cities[i][1] for i in route] + [cities[route[0]][1]]
plt.figure(figsize=(10, 6))
plt.plot(x, y, marker='o')
plt.title("Лучший найденный маршрут (ACO)")
plt.show()
plot_route(best_path)
Генетический алгоритм
import random
import string
# Целевая строка
TARGET = "Hello world!"
# Размер популяции
POPULATION_SIZE = 100
# Вероятность мутации
MUTATION_RATE = 0.01
# Символы, которые могут использоваться
CHARS = string.printable
def random_string(length):
return ''.join(random.choice(CHARS) for _ in range(length))
def fitness(individual):
return sum(1 for expected, actual in zip(TARGET, individual) if expected == actual)
def mutate(individual):
return ''.join(
c if random.random() > MUTATION_RATE else random.choice(CHARS)
for c in individual
)
def crossover(parent1, parent2):
split = random.randint(0, len(TARGET))
return parent1[:split] + parent2[split:]
# Инициализация популяции
population = [random_string(len(TARGET)) for _ in range(POPULATION_SIZE)]
generation = 0
while True:
# Оценка приспособленности
population = sorted(population, key=fitness, reverse=True)
best = population[0]
print(f"Gen {generation}: {best} (fitness: {fitness(best)})")
if best == TARGET:
break
# Отбор лучших и создание новой популяции
new_population = population[:2] # Элитизм: сохранить лучших
while len(new_population) < POPULATION_SIZE:
parents = random.choices(population[:50], k=2) # Скрещивать лучших
child = mutate(crossover(*parents))
new_population.append(child)
population = new_population
generation += 1
Применение к задачи коммивояжера
import random
import math
import matplotlib.pyplot as plt
# ------------------------------
# Настройки задачи
NUM_CITIES = 20
POPULATION_SIZE = 100
GENERATIONS = 500
MUTATION_RATE = 0.01
# ------------------------------
# Генерация случайных координат городов
cities = [(random.uniform(0, 100), random.uniform(0, 100)) for _ in range(NUM_CITIES)]
def distance(a, b):
return math.hypot(a[0] - b[0], a[1] - b[1])
def total_distance(tour):
return sum(distance(cities[tour[i]], cities[tour[(i+1)%NUM_CITIES]]) for i in range(NUM_CITIES))
def create_route():
route = list(range(NUM_CITIES))
random.shuffle(route)
return route
def mutate(route):
if random.random() < MUTATION_RATE:
i, j = random.sample(range(NUM_CITIES), 2)
route[i], route[j] = route[j], route[i]
return route
def crossover(parent1, parent2):
start, end = sorted(random.sample(range(NUM_CITIES), 2))
child = [None] * NUM_CITIES
child[start:end] = parent1[start:end]
ptr = 0
for city in parent2:
if city not in child:
while child[ptr] is not None:
ptr += 1
child[ptr] = city
return child
# Инициализация популяции
population = [create_route() for _ in range(POPULATION_SIZE)]
# Основной цикл
for gen in range(GENERATIONS):
population.sort(key=total_distance)
best = population[0]
print(f"Gen {gen}, Distance: {total_distance(best):.2f}")
# Сохранение лучших и создание потомков
new_population = population[:10]
while len(new_population) < POPULATION_SIZE:
parents = random.choices(population[:50], k=2)
child = mutate(crossover(*parents))
new_population.append(child)
population = new_population
# Визуализация лучшего маршрута
def plot_route(route):
x = [cities[i][0] for i in route] + [cities[route[0]][0]]
y = [cities[i][1] for i in route] + [cities[route[0]][1]]
plt.figure(figsize=(10, 6))
plt.plot(x, y, marker='o')
plt.title("Лучший найденный маршрут")
plt.show()
plot_route(best)
Метод имитации отжига
Список источников