/images/Eevee.png

文章内容若有侵权,请联系删除🌹

代码小整理2

Python 实现差分进化算法

用于解决机场选址优化问题:在 20 个城市中放置 3 个机场,最小化所有城市到最近机场的距离总和

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import random
import numpy as np
import matplotlib.pyplot as plt


def distance(x1, x2):
    """计算两个坐标点的欧氏距离平方(无需开方以优化性能)"""
    return (x1[0] - x2[0]) ** 2 + (x1[1] - x2[1]) ** 2


def total_distance(airports, cities):
    """计算所有城市到最近机场的距离总和(使用向量化计算)"""
    airports_arr = np.array(airports)
    cities_arr = np.array(cities)
    # 计算每个城市到所有机场的平方距离
    diff = cities_arr[:, None, :] - airports_arr[None, :, :]
    dist_sq = np.sum(diff**2, axis=2)
    # 获取每个城市到最近机场的距离
    min_dists = np.min(dist_sq, axis=1)
    return np.sum(min_dists)


# 城市坐标数据集
cities = [
    [91, 492], [400, 327], [253, 288], [165, 299], [562, 293],
    [305, 449], [375, 270], [534, 350], [473, 506], [165, 379],
    [168, 339], [406, 537], [131, 571], [320, 368], [233, 410],
    [207, 457], [94, 410], [456, 350], [509, 444], [108, 531]
]

# 算法参数
POP_SIZE = 50  # 种群规模
MAX_ITER = 10000  # 最大迭代次数

# 记录最佳解和迭代信息
best_global = float("inf")
best_solution = None
no_improve = 0
convergence_data = []
MAX_NO_IMPROVE = 100  # 连续无改进的最大迭代次数

# 获取城市坐标边界
x_coords = [c[0] for c in cities]
y_coords = [c[1] for c in cities]
x_min, x_max = min(x_coords), max(x_coords)
y_min, y_max = min(y_coords), max(y_coords)

# 初始化种群(每个个体包含3个机场坐标)
population = []
for _ in range(POP_SIZE):
    airport1 = [
        round(random.uniform(x_min, x_max), 2),
        round(random.uniform(y_min, y_max), 2),
    ]
    airport2 = [
        round(random.uniform(x_min, x_max), 2),
        round(random.uniform(y_min, y_max), 2),
    ]
    airport3 = [
        round(random.uniform(x_min, x_max), 2),
        round(random.uniform(y_min, y_max), 2),
    ]
    population.append([airport1, airport2, airport3])

# 差分进化主循环
for iter in range(MAX_ITER):
    pop_array = np.array(population)
    new_population = []
    no_improve_flag = True

    # 自适应差分权重(随迭代次数递减)
    F = 0.9 * (1 - iter / MAX_ITER) + 0.4 * (iter / MAX_ITER)

    for individual in population:
        # 变异操作:生成变异向量
        a, b, c = random.choices(population, k=3)
        mutant = a + F * (np.array(b) - np.array(c))
        mutant = mutant.tolist()

        # 交叉操作:生成试验向量
        trial = []
        for j in range(3):
            if random.random() <= 0.5 or j == random.randint(0, 2):
                trial.append(mutant[j])
            else:
                trial.append(individual[j])

        # 选择操作:保留更优解
        current_fitness = total_distance(individual, cities)
        trial_fitness = total_distance(trial, cities)
        if trial_fitness < current_fitness:
            new_population.append(trial)
            # 更新全局最优解
            if trial_fitness < best_global:
                best_global = trial_fitness
                best_solution = np.copy(trial)
                no_improve = 0
                no_improve_flag = False
        else:
            new_population.append(individual)

    population = new_population
    # 记录收敛数据
    convergence_data.append(best_global)

    if no_improve_flag:
        no_improve += 1
        # 检查提前终止条件
        if no_improve >= MAX_NO_IMPROVE:
            print(f"提前终止于第{iter}代,已连续{no_improve}代无改进")
            break

# 结果提取与验证
# 记录最优个体的下标
best_idx = 0
for i in range(len(population)):
    if total_distance(population[i], cities) < total_distance(
        population[best_idx], cities
    ):
        best_idx = i
# 记录次优个体的下标
second_best_idx = 0
for i in range(len(population)):
    if i != best_idx and total_distance(population[i], cities) < total_distance(
        population[second_best_idx], cities
    ):
        second_best_idx = i

# 计算最优个体与次优个体的差值,以判断收敛情况
diff = total_distance(population[second_best_idx], cities) - total_distance(
    population[best_idx], cities
)
print(f"最优解与次优解距离差: {diff:.2f}")
print(f"最优机场坐标: {population[best_idx]}")
print(f"最小距离和: {total_distance(population[best_idx], cities):.2f}")
  • 可视化结果
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 显示中文和负号
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

# 绘制收敛曲线
plt.figure(figsize=(12, 10))
plt.subplot(2, 1, 1)
plt.plot(convergence_data)
plt.title("收敛曲线")
plt.xlabel("迭代次数")
plt.ylabel("最优距离和")
plt.grid(True)

# 可视化结果
plt.figure(figsize=(10, 8))
# 绘制城市
for i, (x, y) in enumerate(cities):
    plt.scatter(x, y, c="b")
    plt.text(x, y, f"({x},{y})", ha="center", va="bottom", fontsize=10)
lines = [
    [12, 19], [19, 0], [12, 15], [0, 15], [0, 16],
    [16, 9], [9, 10], [10, 3], [3, 2], [15, 14],
    [15, 5], [14, 2], [14, 13], [13, 2], [5, 1],
    [13, 1], [1, 6], [1, 17], [17, 7], [7, 4],
    [17, 18], [18, 8], [8, 11]
]
for i in range(len(x_coords)):
    for j in range(len(y_coords)):
        if [i, j] in lines:
            plt.plot([x_coords[i], x_coords[j]], [y_coords[i], y_coords[j]])

# 绘制机场
airport_x = [p[0] for p in population[best_idx]]
airport_y = [p[1] for p in population[best_idx]]
plt.scatter(airport_x, airport_y, c="r", marker="s", s=100)

# 机场-地点连线线
for city in cities:
    closest = min(population[best_idx], key=lambda a: distance(a, city))
    plt.plot([city[0], closest[0]], [city[1], closest[1]], ":", c="gray", alpha=0.5)
plt.title("机场选址优化结果")
plt.xlabel("X 坐标")
plt.ylabel("Y 坐标")
plt.grid(True)
plt.show()

状态空间模型与深度优先搜索

问题的背景是有三名传教士和三名食人族在河的一侧。他们想要过河,但只有一条船,船每次只能搭载两个人
如果在任何时候食人族的数量超过传教士的数量,食人族就会吃掉传教士。此外,船必须有人在河一侧划船才能返回,船不能自己回来
为了解决这个问题,我们将搜索所有可能移动的状态空间,最终只求找到一种可行解就好

代码小整理1

📊 Excel 文件处理

根据字段合并两个 Excel 文件

问题:使用 pandas 读取包含 计算公式 的 Excel 文件时,可能报错:
ValueError: Value does not match pattern ^[$]?([A-Za-z]{1,3})[$]?(\d+)

解决方案:使用 xlwings 库作为备用读取方法,避免计算公式导致的读取错误

VSCode相关问题

参考文章

关于缓存文件的转移

为了减少 C 盘空间占用, 故修改扩展和缓存文件的路径【注意, 移到其他的盘后, 以后启动 VSCode 可能需要管理员权限】
通过创建符号链接(symbolic link)来转移 VSCode 缓存和扩展文件, 让系统认为文件仍在 C 盘原路径, 但实际内容存储在 D 盘。这样 VSCode 能无感知地读写, 同时释放了 C 盘空间
具体步骤如下:

云计算小知识

云计算基础概念

云计算的定义

美国国家标准技术学院(NIST)给出的定义:

云计算是一种模型,可以方便地通过网络访问可配置的计算资源(网络、服务器、存储设备、应用程序、服务等)的公共集。这些资源可以被快速提供和发布,同时最小化管理成本和服务供应商的干预。