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

ChocoSolver求解覆盖所有城市的最少路径约束定义问题

问题根因

你的约束存在两个核心逻辑漏洞,导致求解器可以生成不符合业务规则的无效解:

  • 关联约束覆盖不全,且使用方式冗余易错
    你使用element约束仅关联了「路径实际覆盖的城市」和usedPath变量,完全没有约束两类场景:
    • 未被路径i覆盖的城市,不能选择路径i作为通行路径
    • 若路径i未被选中(usedPath[i]=0),所有城市都不能标记为使用了路径i
      你给出的错误输出就完全命中这两个漏洞:城市1选择了根本不覆盖它的路径0,且路径0/1/3都未被选中,但对应城市的标记位全为1,这些位置没有任何约束限制,求解器为了凑出最小的总路径数,会随意给这些无约束位置赋值1来满足「每个城市至少有一条路径」的要求。
  • element约束属于冗余选型
    对于0/1二元变量的关联场景,用简单的算术约束比element更直观,也不容易出现参数顺序、覆盖范围的错误。

修正方案

方案1:保留原有变量结构,补全约束

你可以直接删除原来错误的element循环块,替换为以下约束即可:

// 第一步:预处理路径-城市覆盖关系,避免重复判断
boolean[][] pathCoverCity = new boolean[nbPath][nbCity];
for (int i = 0; i < nbPath; i++) {
    for (int city : M[i]) {
        pathCoverCity[i][city-1] = true;
    }
}

// 约束:城市不能选择不覆盖自己的路径 + 未被选中的路径所有城市都不能用
for (int pathIdx = 0; pathIdx < nbPath; pathIdx++) {
    for (int cityIdx = 0; cityIdx < nbCity; cityIdx++) {
        if (!pathCoverCity[pathIdx][cityIdx]) {
            // 路径不覆盖该城市,对应标记位必须为0
            model.arithm(city_by_path[cityIdx][pathIdx], "=", 0).post();
        }
        // 未选中的路径,对应城市标记位必须为0
        model.arithm(city_by_path[cityIdx][pathIdx], "<=", usedPath[pathIdx]).post();
    }
}

// 原有两个逻辑正确的约束可直接保留
// 1. 每个城市至少被一条路径覆盖
for(int i = 0; i<nbCity; i++) {
    model.sum(city_by_path[i], ">=", 1).post();
}
// 2. 总路径数统计+最小化目标
model.sum(usedPath, "=", totalPath).post();
model.setObjective(Model.MINIMIZE, totalPath);

以上约束逻辑非常明确:不合法的路径选择(路径不覆盖城市、路径未选中)直接被强制为0,没有自由赋值空间;仅当路径被选中、且路径确实覆盖某城市时,城市才可以标记为使用该路径,最终求解结果符合业务规则。


方案2:简化模型(推荐,移除冗余变量)

你的问题本质是经典的集合覆盖问题,不需要定义二维的city_by_path变量记录每个城市选了哪条路,只需要保证选中路径的覆盖范围包含所有城市即可,模型可以大幅简化、求解效率更高:

Model model = new Model("minimalPaths");
int nbPath = M.length;
int nbCity = 6;
// 仅保留核心变量:路径是否选中、总选中路径数
IntVar[] usedPath = model.intVarArray("path", nbPath, 0, 1);
IntVar totalPath = model.intVar("totalPath", 0, nbPath);

// 预处理每个城市被哪些路径覆盖
List<IntVar>[] coverCityPath = new List[nbCity];
for (int i = 0; i < nbCity; i++) {
    coverCityPath[i] = new ArrayList<>();
}
for (int pathIdx = 0; pathIdx < nbPath; pathIdx++) {
    for (int city : M[pathIdx]) {
        coverCityPath[city-1].add(usedPath[pathIdx]);
    }
}

// 约束1:每个城市至少被一条选中的路径覆盖
for (int cityIdx = 0; cityIdx < nbCity; cityIdx++) {
    model.sum(coverCityPath[cityIdx].toArray(new IntVar[0]), ">=", 1).post();
}
// 约束2:统计总路径数,设置最小化目标
model.sum(usedPath, "=", totalPath).post();
model.setObjective(Model.MINIMIZE, totalPath);

运行该模型会直接输出最优解:选中路径0和路径1,总路径数为2,和预期结果完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:33:23