离婚协议这种人间烟火气最重的事情,居然能用递归函数写出来,我第一次听到这个想法的时候也觉得有点离谱。但仔细一想,作为软件测试出身的工程师,这类“把模糊的现实决策转成精确的计算规则”的问题恰恰是最有意思的挑战。抚养权分割本质上是一个多因素、多约束的组合分配问题,而递归这种“把一个大规模问题拆成结构相同的小问题”的思维,天然就适合建模这类分配逻辑。这篇文章我想从一个软件测试工程师的视角,把整个“递归分割孩子”的建模、实现、鲁棒性设计和测试过程完整讲一遍。内容覆盖核心算法、边界条件、失败注入测试,以及我踩过的几个真实的坑。如果你对算法设计、测试思维、或者“技术如何介入人文决策”这个话题感兴趣,这篇文章应该能给你一些不一样的东西。
1. 问题剖析:为什么“分割孩子”会被我建模成递归问题
1.1 一个容易被误读的“冷酷”需求背后,其实是抽象建模
很多程序员听到“用代码写离婚协议”这种需求,第一反应是“这也太没人情味了”。但实际上,把现实世界的决策规则变成可执行的代码,不是什么冷血行为,而是抽象建模能力的一种体现。抚养权分配涉及的因素极多:孩子的年龄、居住环境稳定性、教育资源的匹配度、父母双方的经济能力和陪伴时间、孩子本人的意愿,甚至还有地域因素。如果我们要做一个辅助决策工具,就必须把这些因素转化为可量化的输入,然后沿着明确的规则去计算。
这里要强调一点:代码只是辅助决策的工具,不是替代法官或当事人做最终判断。我参与过类似的项目后最深的感觉是,算法的价值不是给出一个“正确答案”,而是把所有可行方案和它们的量化指标摊开,让决策者看到一个全局的图谱。有了这个图谱,讨论的焦点就从“我觉得应该怎么分”变成“为什么这个方案在这些指标上更优”,沟通效率会高很多。
1.2 递归的核心思想:把“n个孩子怎么分”拆成“一个孩子怎么分 + 剩下n-1个孩子怎么分”
为什么这个问题适合用递归而不是迭代?最根本的原因是:我们事先不知道有多少个孩子,也不知道每个孩子的归属会对整体分配产生什么连锁影响。递归的思路非常直白——我先把第一个孩子分配给父亲,然后递归处理剩余的孩子;再把第一个孩子分配给母亲,再递归处理剩余的孩子。当剩余孩子数量为0时,就得到了一套完整的分配方案。整个过程其实就是在一棵二叉树上做深度优先遍历,树的每条从根到叶子的路径都代表一个完整的分配方案。
这种拆解方式比起嵌套n层for循环要优雅得多,因为你不需要在编码的时候就知道n是多少。写得好的递归函数,读起来就是一段逻辑自描述的代码:终止条件、状态更新、递归调用、状态恢复。每一步都对应着现实世界里的一个决策步骤。
1.3 定义清楚输入、输出和评估函数,是算法能否落地的关键
编程的第一课就是“先定义数据结构,再写逻辑”。在这个项目里我定义了这样几个输入:
- 每个孩子的唯一标识(不要用姓名,因为可能出现双胞胎同名的情况,要使用ID)
- 孩子的年龄
- 孩子与父亲、母亲分别的“综合匹配度”评分,0到100分
- 孩子的意愿倾向(只支持 father / mother / none 三种)
- 父母双方的“抚养容量”,比如经济能力、居住面积、可投入时间等,同样是0到100分
输出是一个分配方案:每个孩子最终归父亲还是母亲。但单纯输出一个方案还不够,必须同时输出这个方案的两个关键指标:双方总分差和偏好满足度。前者用于衡量“分得是否公平”,后者用于衡量“孩子意愿是否被尊重”。两个指标必须同时展示,因为只追求公平可能会忽视孩子本人的感受,而只追求偏好满足则可能把资源压力全压在其中一方身上。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心算法实现:递归枚举与多方案择优
2.1 数据结构与输入约定
我用了Python来做原型,主要是它的表达力强,适合快速验证想法。数据结构就是一个字典列表,每个孩子一个字典:
python复制children = [
{"id": "C001", "age": 8, "father_match": 85, "mother_match": 78, "preference": "father"},
{"id": "C002", "age": 12, "father_match": 72, "mother_match": 88, "preference": "mother"},
{"id": "C003", "age": 5, "father_match": 90, "mother_match": 91, "preference": "none"},
]
father_capacity = 80 # 父亲的抚养综合容量
mother_capacity = 75 # 母亲的抚养综合容量
这里的 father_match 表示孩子与父亲共同生活的综合匹配度,由教育环境、亲属支持度、生活习惯匹配等子项加权计算得到。father_capacity 是父亲这方可投入的抚养综合能力。二者是不同维度的数据,在评估时需要分开考虑。
2.2 递归枚举所有分配方案
核心枚举逻辑我封装成了一个生成器,用 yield 逐个返回完整方案,避免把所有方案都堆在内存里:
python复制def enumerate_assignments(children):
n = len(children)
assignment = [0] * n # 0 表示父亲,1 表示母亲
def dfs(idx):
if idx == n:
yield tuple(assignment)
return
