项目 文章 归档 动态 友链 关于

爬山算法 × 模拟退火:教室排座工具的寻优之路

S

这个项目的起因是当班主任的朋友一句吐槽:「每次换座位都要权衡四十多个学生的关系,比写代码难多了」。我说:那就交给代码。

把愿望翻译成目标函数

寻优算法的第一步不是选算法,而是定义「好」。我们把老师的直觉拆成可计算的规则,每条规则一个权重:

function score(seats, rules) {
  let total = 0;
  for (const [a, b, w] of rules.pairs) {
    if (isNeighbor(seats, a, b)) total += w; // 想同桌 +w
  }
  return total - penalty(seats, rules.blocks);
}

爬山与退火

先试了最朴素的爬山法:随机交换两个学生,分数变高就接受。实现只要十几行,收敛飞快——但总停在「还行」的方案上。

模拟退火的洞察是:在高温阶段以概率接受更差的解,随温度下降,接受概率趋近于零。设新解与当前解的分数差为 ΔE\Delta E(越低越差),接受劣解的概率:

P(accept)=exp(ΔET)P(\text{accept}) = \exp\left(-\frac{\Delta E}{T}\right)

温度按几何日程衰减:Tk+1=αTkT_{k+1} = \alpha T_k,本项目取 α=0.95\alpha = 0.95、初始 T0=100T_0 = 100。同样是 3 秒预算,爬山法平均分 82,模拟退火 91,且方差明显更小。

工程上的取舍

决策选择代价
运行位置纯前端 WebWorker首次加载多一个文件
数据存储localStorage换设备需导出导入
可视化Canvas 逐帧重绘代码量更多

上线一学期后,朋友的反馈是:「它给出的方案不总是我心里的最优,但从来不会离谱。」——对算法工程来说,这就是好评。

本文作者:Ethan · 发布于 2026-08-15
本文链接:https://example.com/posts/seating-algo/ · 版权声明:CC BY-NC-SA 4.0,转载请注明出处。