注:该内容由“数模加油站”原创,无偿分享,可以领取参考但不要利用该内容倒卖,谢谢!
问题1 请选择合适的数据集,综合考虑气象适宜性、城市承载能力、人口规 模及报名热度(主要由历史报名人数及其增长率体现)等核心要素, 进而科学筛选中国主要城市的马拉松赛事窗口期、合理确定比赛时间、 赛事规模与频次。
问题 1 分析
题目要求“筛选中国主要城市的马拉松赛事窗口期,并合理确定比赛时间、规模与频次”,其实质是一个在多因子综合得分下的约束优化调度问题。
具体而言,我们面临的问题是:
对每个城市(共n个)和每个月份
(共12个月),是否安排比赛?
如果安排,该城市该月应办几次(频次)?
总体目标是在限制资源下最大化全国马拉松赛事整体效益得分。
这个问题具有以下典型特征:
决策变量是离散的0/1或整数选择;
有组合爆炸性(全国若干城市×12个月);
同时存在多个实际业务约束;
涉及多城市多时间窗口的离散组合优化问题,具有高维决策空间与复杂的逻辑约束,使其难以用传统解析方法或线性规划精确求解。
因此,本题非常适合遗传算法建模
解题思路:
1.染色体设计:将“城市-月份-频次”决策结构编码为优化基因
在第一问中,我们面对的核心决策问题是:在哪些城市的哪些月份安排马拉松赛事?每月举办多少次?
这类组合调度问题具有天然的“时空交叉”结构——横向为12个月份,纵向为若干城市。为了让智能优化算法能够有效处理,我们需要将这种二维结构转化为适用于算法操作的一维“染色体”形式。
问题结合:
每一个染色体个体代表一整年的全国马拉松赛事安排计划,类似于制定一个年度“马拉松日历”。染色体中的每一个“基因”元素代表“某城市某月份的赛事频次”,取值范围为0(不举办)至3(最多举办三次)。
结构设计:
假设共有 N 个城市(可根据数据筛选得出如50个),则染色体长度为;
每个位置存储整数,即第 i 城市在第 j 月的办赛频次;
编码为一维向量,便于遗传算法交叉与变异操作。
这种结构设计确保了:模型具有可解释性、灵活性强、易于扩展到新城市或变动月份范围,非常适合数据驱动与策略制定场景。
2.适应度函数:以综合赛事价值为优化目标的构造逻辑
适应度函数是遗传算法评价“方案好坏”的标准。在本题中,一个优秀的赛事安排方案应当同时满足:
- 举办时间与气候适宜;
- 城市具备承载与服务能力;
- 有足够的群众基础与参赛热情;
- 比赛频次适度,不资源过载。
问题结合:
题干中明确提到“高温会降低参赛体验”“交通承载力影响赛事安全”“人口与报名数据反映热度”——这些都可以被量化为一个“综合赛事得分” ,作为评价城市
在月份
举办赛事的价值函数。
适应度函数即为:全国所有比赛安排所带来的总收益:
这里每一项代表城市 i 在月 j 举办 次比赛带来的“城市-月份”收益。此设计充分尊重题目提出的“窗口期+赛事价值最大化”的指导思想,确保优化方向贴合题意。
3. 约束机制设计:将实际限制转换为数学规则嵌入模型
本题中的安排问题不是“越多越好”,而是要在多个约束下取得最优方案。
问题结合:
题目中提到“2024年长沙马拉松吸引15万人报名”,但“城市承载能力有限”;这就说明单一城市赛事安排频次必须控制;
同时,“11月举办114场赛事”,但“拥堵”风险暗示单月过度集中安排不可取;
因此,必须将这些真实运行规律转化为模型约束。
约束转化:
单城频次约束:
每个城市全年办赛不超过6次,避免资源过度集中。
单月规模限制:
每月全国赛事城市不超过10个,控制全国交通与转播资源调度压力。
数据可兼容性约束(编码限制):
保证频次值为0–3之间的整数,防止非法染色体。
通过构造惩罚函数:
4. 遗传操作机制:策略生成与进化过程的细节定制
问题结合:
初始种群生成代表“多个初步方案备选”;
交叉操作相当于从不同城市的安排经验中“择优借鉴”;
变异操作模拟“政策微调与试验机制”;
精英保留策略体现“经验沉淀与政策延续性”。
操作细节优化:
选择机制(轮盘赌/锦标赛):优先保留总得分高的赛程规划;
城市片段交叉法:将城市为单位进行赛程模板组合,保留整体逻辑;
可行性修复机制:交叉或变异后自动检查约束,若违反则纠偏或放弃。
Python代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import random
from typing import Tuple
# ========== 参数设置 ==========
N = 10 # 城市数量(可替换为真实城市列表长度)
M = 12 # 月份数量
POP_SIZE = 50
MAX_GEN = 100
MUTATE_PROB = 0.1
CROSSOVER_PROB = 0.8
MAX_CITY_EVENTS = 6
MAX_MONTH_EVENTS = 10
# ========== 构造评分矩阵S_ij(模拟气候、热度、承载) ==========
np.random.seed(42)
S_matrix = np.random.rand(N, M) # 若有真实数据,请在此处替换为实际评分矩阵
# ========== 个体生成 ==========
def generate_individual() -> np.ndarray:
individual = np.zeros((N, M), dtype=int)
for i in range(N):
total = 0
for j in range(M):
if total >= MAX_CITY_EVENTS:
break
if random.random() < 0.3:
f = random.randint(1, 3)
if total + f <= MAX_CITY_EVENTS:
individual[i, j] = f
total += f
return individual
# ========== 适应度函数 ==========
def fitness(individual: np.ndarray) -> float:
base_score = np.sum(individual * S_matrix)
# 城市约束惩罚
city_penalty = 0
for i in range(N):
total_events = np.sum(individual[i, :])
if total_events > MAX_CITY_EVENTS:
city_penalty += (total_events - MAX_CITY_EVENTS)
# 月度约束惩罚
month_penalty = 0
for j in range(M):
cities = np.sum(individual[:, j] > 0)
if cities > MAX_MONTH_EVENTS:
month_penalty += (cities - MAX_MONTH_EVENTS)
penalty = 10 * (city_penalty + month_penalty)
return base_score - penalty
# ========== 遗传操作 ==========
def crossover(parent1: np.ndarray, parent2: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
point = random.randint(1, N - 1)
child1 = np.vstack((parent1[:point], parent2[point:]))
child2 = np.vstack((parent2[:point], parent1[point:]))
return child1, child2
def mutate(individual: np.ndarray) -> np.ndarray:
i = random.randint(0, N - 1)
j = random.randint(0, M - 1)
individual[i, j] = random.randint(0, 3)
return individual
# ========== 初始化种群 ==========
population = [generate_individual() for _ in range(POP_SIZE)]
best_fitness_list = []
# ========== 主进化过程 ==========
for gen in range(MAX_GEN):
population.sort(key=fitness, reverse=True)
next_gen = population[:2] # 精英保留
while len(next_gen) < POP_SIZE:
p1, p2 = random.sample(population[:20], 2)
if random.random() < CROSSOVER_PROB:
c1, c2 = crossover(p1, p2)
else:
c1, c2 = p1.copy(), p2.copy()
if random.random() < MUTATE_PROB:
c1 = mutate(c1)
if random.random() < MUTATE_PROB:
c2 = mutate(c2)
next_gen.extend([c1, c2])
population = next_gen[:POP_SIZE]
best_fitness = fitness(population[0])
best_fitness_list.append(best_fitness)
# ========== 最优方案展示 ==========
best_individual = population[0]
df_result = pd.DataFrame(best_individual, columns=[f"Month {m+1}" for m in range(M)])
df_result["City"] = [f"City {i+1}" for i in range(N)]
df_result.set_index("City", inplace=True)
# 打印排布方案
print("最优城市-月份赛事安排频次:")
print(df_result)
# ========== 适应度变化图 ==========
plt.figure(figsize=(10, 5))
plt.plot(best_fitness_list, label="Best Fitness")
plt.xlabel("Generation")
plt.ylabel("Fitness Score")
plt.title("GA Optimization Progress for Marathon Scheduling")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
后续都在“数模加油站”......