从数学层面彻底理解:为什么看似不同的算式,其实是同一种解法
在24点游戏中,穷举算法往往会生成大量本质上等价的解法。例如对于数字 1, 2, 3, 4:
(1 + 2 + 3) × 4 = 244 × (3 + 2 + 1) = 24(2 + 1 + 3) × 4 = 24这三条算式在数学上完全等价——它们都是"把1、2、3加起来,再乘以4"。如果把它们当作三种不同解法展示给用户,会让结果列表充斥冗余信息,干扰用户找到真正有价值的解法。
🎯 去重的目标:识别并合并数学上等价的算式,只保留有意义的、本质不同的解法。
"运算指纹"是一种用数学特征值来唯一标识算式本质的方法。
核心思想很简单:
💡 一个算式的数学本质,由它的运算结构和每个数字的位置共同决定。
如果两条算式只是交换律、结合律层面的变形,它们的"运算指纹"一定是相同的。
对于算式A和B:
(a + b + c) × d,其中 a,b,c 是 {1,2,3},d 是 4而算式C的运算结构完全不同,它是一条不同的解法。
本系统采用数值替换 + 表达式求值的方式生成运算指纹,具体分为以下步骤:
1为每个数字分配"指纹值"
系统为 1∼13 每个数字预先分配一个唯一的伪随机浮点数作为指纹值。例如:
这些指纹值由稳定的哈希算法生成,确保每次运行时同一数字得到同样的指纹值。
2替换算式中的数字
将算式中每个数字替换为对应的指纹值,形成一条指纹表达式:
3计算指纹结果
对指纹表达式执行 eval 求值,得到一个浮点数——这就是该算式的"运算指纹"。
4按指纹去重
将每条算式的运算指纹作为 key 存入哈希表。相同指纹的算式只保留第一条,从而实现去重。
这是指纹去重最精妙的地方:
以数字 6, 6, 6, 6 为例,穷举得到 168 种解法:
| # | 去重前(部分示例) | 指纹 | 说明 |
|---|---|---|---|
| 1 | 6 + 6 + 6 + 6 | 相同 | 这四条本质上都是"四个6相加",被合并为1条 |
| 2 | (6 + 6) + (6 + 6) | 相同 | |
| 3 | 6 + (6 + 6 + 6) | 相同 | |
| 4 | (6 + 6 + 6) + 6 | 相同 | |
| 5 | 6 × 6 - 6 - 6 | 不同 | 本质不同的解法,独立保留 |
| 6 | 6 × 6 ÷ 6 × 6 | 不同 | 本质不同的解法,独立保留 |
最终,168 种穷举结果经指纹去重后可能只剩十几条真正不同的解法。
| 对比维度 | 🔍 指纹去重 | 🤖 大模型去重 |
|---|---|---|
| 原理 | 数学层面:基于运算结构的数值特征 | 语义层面:基于AI对数学表达式的理解 |
| 速度 | 极快,毫秒级完成 | 较慢,需调用远程AI接口 |
| 准确性 | 严格数学等价,不会误删有效解法 | 依赖模型能力,可能过度去重或漏掉 |
| 局限性 | 仅能识别结构等价,不判断"是否人类友好" | 可判断解法是否简洁、自然 |
| 适用场景 | 快速预处理,大幅减少候选解法 | 精选最优解法,提供推理依据 |
指纹去重是一种轻量、高效、数学上严谨的去重方法。它不依赖任何外部AI服务,在本地毫秒级完成,能够将穷举算法产出的几百条解法瞬间压缩到十几条真正不同的解法,为后续的大模型精选提供高质量的输入。
在实际使用中,指纹去重是大模型去重的绝佳前置步骤——先用指纹去重快速过滤掉冗余,再将精简后的解法交给AI做语义级精选,兼顾效率与质量。