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

CLPFD能否实现物品均匀分组?负载均衡求解问询

CLPFD 重量均衡分组解决方案

问题分析

你的代码出现非预期结果的核心原因有两点:

  • labeling/2 调用方式错误:将派生变量 TableDiff 放入待标记变量列表,CLPFD 的 min(Expr) 选项需要直接针对影响目标的决策变量(即台面分配列表 Tables)生效,而非派生的差异值。
  • balance/3 实现冗余:递归遍历的写法既低效又容易引入约束传播问题,完全可以用 CLPFD 内置的求和约束替代。

优化后的实现方案

以下是修正后的代码,同时优化了约束逻辑,确保优先找到负载差异最小的分组:

% 定义重量数据
weight(10).
weight(10).
weight(10).
weight(10).

go(Pairs) :-
    % 提取重量数值列表,而非封装后的weight(Kg)结构
    findall(Kg, weight(Kg), KgList),
    length(KgList, N),
    % 生成对应每个重量的台面分配变量(1或2)
    length(Tables, N),
    Tables ins 1..2,
    % 计算总重量
    sum(KgList, #=, Total),
    % 计算台面1的总负载:遍历每个重量,若分配到1则累加对应Kg
    T1 #= sum( [ Kg * (T #= 1) || Kg, T <- zip(KgList, Tables) ] ),
    % 台面2的总负载 = 总重 - 台面1负载
    T2 #= Total - T1,
    % 定义负载差异目标
    TableDiff #= abs(T1 - T2),
    % 核心:优先最小化TableDiff,再标记分配变量
    labeling([min(TableDiff)], Tables),
    % 将重量与分配结果组合成预期的Pair格式
    pairs_keys_values(Pairs, [weight(Kg) || Kg <- KgList], Tables).

% 辅助谓词:将两个列表按位置配对
zip([], [], []).
zip([X|Xs], [Y|Ys], [X-Y|Zs]) :-
    zip(Xs, Ys, Zs).

关键改进点说明

  • 简化负载计算:用 sum/3 和逻辑表达式 (T #= 1) 直接计算台面1的总负载,替代递归的 balance/3,约束传播更高效。
  • 修正标记逻辑:labeling/2 仅针对决策变量 Tables,通过 min(TableDiff) 选项告知CLPFD优先探索使差异最小的分配方案。
  • 数据结构优化:先提取纯数值的重量列表,减少不必要的结构封装,提升代码可读性和运行效率。

测试验证

对于4个10Kg的测试用例,运行 go(P) 会返回预期结果:

P = [weight(10)-1, weight(10)-1, weight(10)-2, weight(10)-2]

对于无法完全均衡的场景(如10,9,8,7),代码会优先返回负载差异为0的分组(10+7=17,9+8=17),符合需求。

额外优化建议

如果重量数据量较大,可以在 labeling/2 中添加 ff(首失败)策略,进一步提升搜索效率:

labeling([min(TableDiff), ff], Tables)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 21:43:24