前言
"全球校园人工智能算法精英大赛"是江苏省人工智能学会举办的面向全球具有正式学籍的全日制高等院校及以上在校学生举办的算法竞赛。其中的算法巅峰赛属于产业命题赛道,这是第3赛季,这次优化题的主题是 "碳中和"。

回顾
第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--碳中和
这次采用 整数线性规划 的思路来求解。
和其他算法不同的是,这使用google的OR-Tools库来构建,在小数据集扮演一个天花板角色,大数据则扮演一个参考角色。
OR-Tools
OR-Tools 是 Google 开源的一个运筹学优化工具包,专门用于解决组合优化问题。它内部大量使用了启发式算法和元启发式算法。
主要特点:
车辆路径问题(VRP)求解器:使用多种启发式算法生成初始解,包括最邻近法(Nearest Neighbor)、节约算法(Savings)、扫描法(Sweep)、Christofides 算法等
局部搜索算子:通过邻域搜索不断改进解,并配合元启发式策略(如引导式局部搜索、禁忌搜索、模拟退火)来跳出局部最优
CP-SAT 求解器:结合约束传播与启发式搜索,在 MiniZinc 挑战赛中多次夺金
开源地址:https://github.com/google/or-tools/
数学模型建立
问题分析
在碳中和服务器任务调度场景中,系统需要在满足服务器功耗上限、散热上限以及相邻服务器热传导约束的前提下,将若干计算任务分配至多个服务器,使得总收益最大化。任务具有独占性,即一个任务最多只能分配到一台服务器执行;服务器之间存在热耦合效应,相邻机器的发热量会按一定比例相互影响。该问题属于典型的0-1 整数线性规划问题(Integer Linear Programming, ILP),具有离散决策、多约束、线性目标的特征。
符号定义
设:
- 任务集合 I = { 1 , 2 , ... , N } I = \{1,2,\dots,N\} I={1,2,...,N}
- 服务器集合 J = { 1 , 2 , ... , M } J = \{1,2,\dots,M\} J={1,2,...,M}
- p i p_i pi:任务 i i i 执行后可获得的收益
- w i w_i wi:任务 i i i 运行时产生的功耗
- h i h_i hi:任务 i i i 运行时产生的发热量
- W j W_j Wj:服务器 j j j 允许的最大功耗上限
- H j H_j Hj:服务器 j j j 允许的最大综合热量上限
- α \alpha α:相邻服务器之间的热传导系数
决策变量
定义 0-1 变量 x i j x_{ij} xij 表示任务分配关系:
x i j = 1 x_{ij}=1 xij=1,任务 i i i 被分配至服务器 j j j 执行;
x i j = 0 x_{ij}=0 xij=0,任务 i i i 不分配至服务器 j j j。
其中 \\forall i\\in I,,j\\in J 。
目标函数构建与推导
模型以系统总收益最大化 为优化目标。对于每个任务 i i i,若被分配至任意服务器 j j j 执行,则贡献收益 p i p_i pi;若不被分配,则无收益。
总收益公式为:
max Z = ∑ i ∈ I ∑ j ∈ J p i x i j \max Z = \sum_{i\in I}\sum_{j\in J} p_i x_{ij} maxZ=i∈I∑j∈J∑pixij
推导说明
目标函数为线性加权和形式,权重为任务收益,变量为 0-1 分配变量。该式直接反映了"尽可能选择高价值任务并合法分配"的调度目标,符合碳中和场景下收益优先、约束合规的优化逻辑。
约束条件构建与推导
任务唯一性约束
每个任务最多只能分配到一台服务器,不能同时在多台机器上运行:
∑ j ∈ J x i j ≤ 1 , ∀ i ∈ I \sum_{j\in J} x_{ij} \le 1,\quad \forall i\in I j∈J∑xij≤1,∀i∈I
推导说明
当 ∑ j x i j = 1 \sum_j x_{ij}=1 ∑jxij=1 时,任务被分配到唯一一台服务器;当 ∑ j x i j = 0 \sum_j x_{ij}=0 ∑jxij=0 时,任务不被调度。该约束杜绝任务重复分配,保证调度合理性。
服务器功耗上限约束
服务器 j j j 上所有任务总功耗不超过硬件功耗上限:
∑ i ∈ I w i x i j ≤ W j , ∀ j ∈ J \sum_{i\in I} w_i x_{ij} \le W_j,\quad \forall j\in J i∈I∑wixij≤Wj,∀j∈J
推导说明
该约束限制单台服务器负载功耗,防止硬件过载,保障机房设备稳定运行。
服务器自身产热计算
服务器 j j j 自身任务产生的总热量:
H j s e l f = ∑ i ∈ I h i x i j H_j^{self} = \sum_{i\in I} h_i x_{ij} Hjself=i∈I∑hixij
热传导与综合热量约束
服务器存在邻机热传导效应,综合热量由本机产热、左右邻机导热共同构成。
普通服务器热量公式:
H j t o t a l = H j s e l f + α H j − 1 s e l f + α H j + 1 s e l f H_j^{total} = H_j^{self} + \alpha H_{j-1}^{self} + \alpha H_{j+1}^{self} Hjtotal=Hjself+αHj−1self+αHj+1self
首台服务器无左侧热源:
H 1 t o t a l = H 1 s e l f + α H 2 s e l f H_1^{total} = H_1^{self} + \alpha H_2^{self} H1total=H1self+αH2self
末尾服务器无右侧热源:
H M t o t a l = H M s e l f + α H M − 1 s e l f H_M^{total} = H_M^{self} + \alpha H_{M-1}^{self} HMtotal=HMself+αHM−1self
所有服务器综合热量需满足温度上限:
H j t o t a l ≤ H j , ∀ j ∈ J H_j^{total} \le H_j,\quad \forall j\in J Hjtotal≤Hj,∀j∈J
展开完整热量约束公式:
∑ i ∈ I h i x i j + α ∑ i ∈ I h i x i , j − 1 + α ∑ i ∈ I h i x i , j + 1 ≤ H j \sum_{i\in I} h_i x_{ij} + \alpha \sum_{i\in I} h_i x_{i,j-1} + \alpha \sum_{i\in I} h_i x_{i,j+1} \le H_j i∈I∑hixij+αi∈I∑hixi,j−1+αi∈I∑hixi,j+1≤Hj
推导说明
该约束为本问题核心特色约束,模拟真实机房密集部署的热耦合现象,保证服务器温度不超标,满足碳中和节能温控要求。
变量值域约束
所有分配变量为离散 0-1 整数变量:
x i j ∈ { 0 , 1 } x_{ij} \in \{0,1\} xij∈{0,1}
完整整数线性规划模型
整合目标函数与全部约束,最终数学模型如下:
目标函数:
max Z = ∑ i ∈ I ∑ j ∈ J p i x i j \max Z = \sum_{i\in I}\sum_{j\in J} p_i x_{ij} maxZ=i∈I∑j∈J∑pixij
约束条件:
∑ j ∈ J x i j ≤ 1 \sum_{j\in J} x_{ij} \le 1 j∈J∑xij≤1
∑ i ∈ I w i x i j ≤ W j \sum_{i\in I} w_i x_{ij} \le W_j i∈I∑wixij≤Wj
∑ i ∈ I h i x i j + α ∑ i ∈ I h i x i , j − 1 + α ∑ i ∈ I h i x i , j + 1 ≤ H j \sum_{i\in I} h_i x_{ij} + \alpha \sum_{i\in I} h_i x_{i,j-1} + \alpha \sum_{i\in I} h_i x_{i,j+1} \le H_j i∈I∑hixij+αi∈I∑hixi,j−1+αi∈I∑hixi,j+1≤Hj
x i j ∈ { 0 , 1 } x_{ij} \in \{0,1\} xij∈{0,1}
实现
先申明: 该代码不能在比赛中使用(因为没有ortools库)
ortools库依赖:
shell
python -m pip install ortools
代码由Deepseek生成
python
from ortools.linear_solver import pywraplp
def solve_server_task_allocation(N, M, K, tasks, servers):
"""
tasks: list of (profit, power, heat)
servers: list of (power_limit, heat_limit)
"""
# 创建求解器
solver = pywraplp.Solver.CreateSolver('SCIP')
if not solver:
print("SCIP not available, try CBC")
solver = pywraplp.Solver.CreateSolver('CBC')
if not solver:
print("CBC not available, fallback to GLOP (may have rounding issues)")
solver = pywraplp.Solver.CreateSolver('GLOP')
# 决策变量: x[i][j] 任务i分配到服务器j (j从0到M-1)
# 为了方便,服务器索引 0..M-1
x = {}
for i in range(N):
for j in range(M):
x[(i, j)] = solver.BoolVar(f'x_{i}_{j}')
# 不执行: 用sum_{j} x[i][j] <= 1 表示,剩余的不执行
# 辅助变量: 每台服务器的总功耗、总任务热量
task_power = [solver.NumVar(0, servers[j][0], f'power_{j}') for j in range(M)]
task_heat = [solver.NumVar(0, sum(t[2] for t in tasks), f'heat_{j}') for j in range(M)]
# 实际承受热量(含传导)
total_heat = [solver.NumVar(0, servers[j][1], f'total_heat_{j}') for j in range(M)]
# 约束1: 每个任务最多分配到一个服务器
for i in range(N):
solver.Add(sum(x[(i, j)] for j in range(M)) <= 1)
# 约束2: 任务功耗和热量累加到服务器
for j in range(M):
# 功耗累计
power_expr = solver.Sum(tasks[i][1] * x[(i, j)] for i in range(N))
solver.Add(task_power[j] == power_expr)
# 功耗上限
solver.Add(task_power[j] <= servers[j][0])
# 热量累计
heat_expr = solver.Sum(tasks[i][2] * x[(i, j)] for i in range(N))
solver.Add(task_heat[j] == heat_expr)
# 约束3: 热传导公式
for j in range(M):
heat_expr = task_heat[j]
if j > 0:
heat_expr += K * task_heat[j - 1]
if j < M - 1:
heat_expr += K * task_heat[j + 1]
solver.Add(total_heat[j] == heat_expr)
# 热量阈值
solver.Add(total_heat[j] <= servers[j][1])
# 目标: 最大化总收益
objective = solver.Sum(tasks[i][0] * x[(i, j)] for i in range(N) for j in range(M))
solver.Maximize(objective)
solver.SetTimeLimit(600 * 1000) # 注意:单位是毫秒
# 求解
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
# 提取分配结果
assignment = []
for i in range(N):
assigned = 0
for j in range(M):
if x[(i, j)].solution_value() > 0.5:
assigned = j + 1 # 输出从1开始编号
break
assignment.append(assigned)
return assignment
elif status == pywraplp.Solver.FEASIBLE:
# 提取分配结果
assignment = []
for i in range(N):
assigned = 0
for j in range(M):
if x[(i, j)].solution_value() > 0.5:
assigned = j + 1 # 输出从1开始编号
break
assignment.append(assigned)
return assignment
else:
print(f"No optimal solution found. Status: {status}")
return None
def main():
N, M, K = map(float, input().split())
N, M = int(N), int(M)
tasks = []
for i in range(1, N + 1):
p, pw, h = map(int, input().split())
tasks.append((p, pw, h))
servers = []
for i in range(N + 1, N + M + 1):
pw_lim, h_lim = map(int, input().split())
servers.append((pw_lim, h_lim))
result = solve_server_task_allocation(N, M, K, tasks, servers)
if result:
print(' '.join(str(r) for r in result))
if __name__ == "__main__":
main()
效果评估
整数线性规划属于精确解(正解)
它在小数据下,能给出的最优解,但是大数据下,则为近似解,在时间不足下甚至无解。
| 问题类型 | 变量数量 | 约束数量 | 求解时间 | 适用场景 |
|---|---|---|---|---|
| 极小规模 | < 100 | < 200 | < 1秒 | 教学示例、简单验证 |
| 小规模 | 100-500 | 200-1000 | 1-30秒 | 原型验证、小实例 |
| 中规模 | 500-2000 | 1000-5000 | 30秒-10分钟 | 中等规模实际应用 |
| 大规模 | 2000-5000 | 5000-20000 | 10分钟-数小时 | 优化问题边界 |
| 超大规模 | > 5000 | > 20000 | 数小时-数天 | 几乎不可行 |
我们给每个case 10分钟,来对比之前最优解和整数线性规划解。
| Method | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Score |
|---|---|---|---|---|---|---|---|---|---|---|---|
| or-tools | 13.0 | 27.11 | 25.89 | 39.83 | 38.88 | 43.39 | 53.29 | 68.04 | 68.70 | 97.45 | 475.58 |
| 启发式算法 | 13.0 | 27.11 | 25.83 | 39.53 | 38.00 | 41.47 | 53.89 | 66.74 | 69.70 | 95.53 | 470.80 |
| 多策略混合(赛后版) | 13.0 | 25.85 | 25.57 | 38.31 | 37.34 | 41.15 | 53.72 | 66.17 | 70.54 | 95.84 | 467.49 |
| 多策略混合(赛时440+) | 13.0 | 26.98 | 25.68 | 38.65 | 37.18 | 40.54 | 52.46 | 64.65 | 68.73 | 91.65 | 459.52 |
备注:
- 前6个case采用SCIP求解器,后4个采用CBC求解器。
- 前3个case属精确解,后续7个case因数据规模属近似解。

从结果来看,还是相当不错。
QA
-
那这个整数线性规划,是否可以用c++实现呢?
Deepseek 强烈不推荐,涉及的知识点太多,自己实现需要3000+行,尤其在比赛中。
写在最后
