我试图使用进化算法解决N皇后问题,但无法得到我图表中期望的输出结果。
以下是我编写的代码
import matplotlib.pyplot as pltimport randomimport numpy as np# ConstantsN = 8 # Size of the N-Queens problemPOP_SIZE = 100 # Population sizeGENERATIONS = 1000 # Number of generationsMUTATION_PROBABILITIES = [0.6, 0.8, 1.0] # Mutation probabilities# Fitness function to maximize non-attacking pairs def fitness(solution): non_attacking_pairs = 0 for i in range(N): for j in range(i + 1, N): if solution[i] != solution[j] and abs(i - j) != abs(solution[i] - solution[j]): non_attacking_pairs += 1 return non_attacking_pairs # Return the number of non-attacking pairsdef generate_population(): return [random.sample(range(N), N) for _ in range(POP_SIZE)]def select_parents(population): # Tournament selection for parents tournament = random.sample(population, 5) parent = max(tournament, key=fitness) # Maximizing fitness return parentdef crossover(parent1, parent2): point = random.randint(1, N - 1) child1 = parent1[:point] + [x for x in parent2 if x not in parent1[:point]] child2 = parent2[:point] + [x for x in parent1 if x not in parent2[:point]] return child1, child2def mutate(solution, mutation_rate): if random.random() < mutation_rate: i, j = random.sample(range(N), 2) solution[i], solution[j] = solution[j], solution[i] return solutiondef next_generation(population, mutation_rate): new_population = [] # Sort the population by fitness in descending order sorted_population = sorted(population, key=fitness, reverse=True) # Select parents and create the new population while len(new_population) < POP_SIZE: parent1 = select_parents(sorted_population) parent2 = select_parents(sorted_population) child1, child2 = crossover(parent1, parent2) # Mutate the children new_population.append(mutate(child1, mutation_rate)) new_population.append(mutate(child2, mutation_rate)) return new_population# Evolutionary Algorithm with tracking of fitness valuesdef evolutionary_algorithm(mutation_rate): population = generate_population() best_fitness_values = [] average_fitness_values = [] for generation in range(GENERATIONS): # Evaluate fitness of current population fitness_values = [fitness(individual) for individual in population] best_fitness = max(fitness_values) # Maximization average_fitness = np.mean(fitness_values) # Record best and average fitness best_fitness_values.append(float(best_fitness)) # Keep as float average_fitness_values.append(float(average_fitness)) # Keep as float # Generate the next generation population = next_generation(population, mutation_rate) return best_fitness_values, average_fitness_values# Store average fitness values across mutation ratesoverall_average_fitness = np.zeros(GENERATIONS)# Run the evolutionary algorithm for each mutation probabilityfor mutation_rate in MUTATION_PROBABILITIES: best_fitness, average_fitness = evolutionary_algorithm(mutation_rate) # Accumulate average fitness values overall_average_fitness += np.array(average_fitness)# Calculate the overall average fitness across mutation ratesoverall_average_fitness /= len(MUTATION_PROBABILITIES)# overall_average_fitness = np.round(overall_average_fitness)# Plotting the resultsplt.figure(figsize=(12, 6))plt.plot(range(GENERATIONS), overall_average_fitness, label='Overall Average Fitness', color='blue')plt.title('Overall Average Non-Attacking Pairs Fitness Over Generations')plt.xlabel('Generation')plt.ylabel('Fitness (Number of Non-Attacking Pairs)')plt.xticks(ticks=np.arange(0, GENERATIONS + 1, 100)) # Set x-axis ticks at intervals of 10plt.grid()plt.axhline(y=N * (N - 1) / 2 + 0.001, color='black', linewidth=0.1, linestyle='--', label='Max Non-Attacking Pairs') # Max pairs lineplt.legend()plt.show()
我尝试更改了种群大小和代数值,但仍然无法得到平滑的曲线。我的输出:我的输出
期望的输出适应度随代数变化:期望的输出曲线
如何使该曲线看起来平滑?
回答:
为什么要对不同突变率(特别是较大的突变率)进行平均处理?如果你想要一条平滑的曲线,你需要一个较大的种群大小来减少统计噪声,同时你还希望采取小的步骤,因此需要一个较小的突变率,最后你不需要太多的代数,只需要足够达到最大适应度即可:
POP_SIZE = 1000 # Population sizeGENERATIONS = 50 # Number of generationsMUTATION_PROBABILITIES = [0.001] # Mutation probabilities