You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MiniZinc中实现数组折叠,简化密码算术求和?

在MiniZinc中实现类似Haskell fold的密码算术求和方法

问题描述

在MiniZinc中编写密码算术题时,通常需要手动展开求和约束,比如经典的SEND+MORE=MONEY案例:

constraint           1000 * S + 100 * E + 10 * N + D
                   + 1000 * M + 100 * O + 10 * R + E
       = 10000 * M + 1000 * O + 100 * N + 10 * E + Y;

这种手动编写的方式仅适用于单个简单场景,当需要处理更多密码算术题时,效率极低。希望能实现类似Haskell中foldl的功能,通过变量列表自动计算对应的数值,例如Haskell中可通过以下代码将列表转为数字:

ghci> foldl (\x y -> 10 * x + y) 0 [1, 3, 4, 1, 5]
13415

实现方案

MiniZinc虽无原生fold函数,但可通过递归函数或数组求和的方式实现等效功能,以下是两种实用方案:

方案1:递归函数实现

通过递归函数模拟foldl的累加逻辑,将数字列表转换为对应数值:

function var int: list_to_num(array[int] of var int: digits) =
  if length(digits) == 0 then
    0
  else
    list_to_num(array1d(digits[1..length(digits)-1])) * 10 + digits[length(digits)]
  endif;

使用示例(SEND+MORE=MONEY):

% 声明变量
var 0..9: S; var 0..9: E; var 0..9: N; var 0..9: D;
var 0..9: M; var 0..9: O; var 0..9: R; var 0..9: Y;

% 约束条件:首位不能为0,所有变量唯一
constraint S != 0 /\ M != 0;
constraint alldifferent([S,E,N,D,M,O,R,Y]);

% 用递归函数构建求和约束
constraint list_to_num([S,E,N,D]) + list_to_num([M,O,R,E]) = list_to_num([M,O,N,E,Y]);

solve satisfy;
output [
  "SEND = ", show(S), show(E), show(N), show(D), "\n",
  "MORE = ", show(M), show(O), show(R), show(E), "\n",
  "MONEY = ", show(M), show(O), show(N), show(E), show(Y)
];

方案2:数组求和推导式

通过数组推导式计算每一位的权重并累加,逻辑更直观:

function var int: list_to_num(array[int] of var int: digits) =
  sum(i in index_set(digits)) (
    digits[i] * pow(10, length(digits) - i)
  );

该方案利用pow函数计算10的幂次,直接对每一位数字乘以对应权重后求和,无需递归。

注意事项

  • 递归函数方案更贴近Haskell fold的核心逻辑,数组求和方案则更易理解和调试。
  • 确保变量列表的顺序与数字的高位到低位一致(如[S,E,N,D]对应四位数SEND)。

内容的提问来源于stack exchange,提问作者AndrewShulaev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 19:02:06