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

行程路线分组(集合覆盖问题)求解算法及实现方案咨询

适用算法

该问题属于带多目标优化的集合覆盖问题,是NP难问题,根据你的路线规模可以选两类算法:

  1. 小规模场景(路线数≤20):用回溯+剪枝的精确求解算法,可以保证拿到全局最优解,完全满足「优先覆盖城市最多、其次路线数量最少」的要求。
  2. 中大规模场景(路线数>20):用贪心近似算法,虽然不能100%保证全局最优,但运算速度快,工程落地实用性高,大部分场景下输出结果和最优解差距极小。
实现思路

前置预处理

先对输入做两步清洗,减少后续计算量:

  • 把每条路线转换为对应的覆盖城市集合,过滤掉完全不包含任何目标城市的无效路线
  • 剔除冗余路线:如果路线A的覆盖城市集合完全包含路线B的覆盖集合,直接删掉路线B,选A的收益永远高于选B

精确求解(回溯+剪枝)逻辑

  1. 定义最优解判定优先级:首先比较覆盖的目标城市数量,数量越大越优;如果覆盖数量相同,路线条数越少越优
  2. 递归遍历所有可能的路线组合,维护两个全局变量记录当前最优解的覆盖城市数、路线数
  3. 剪枝优化:如果当前已选路线数已经大于等于当前最优解的路线数,直接终止该分支的遍历;如果当前剩余所有路线的总覆盖城市数+已覆盖城市数小于当前最优解的覆盖数,直接终止该分支的遍历

贪心近似(工程常用)逻辑

  1. 初始化已覆盖目标城市集合为空,结果路线列表为空,剩余待覆盖城市为全部目标城市
  2. 每次从未选中的路线里,选出能覆盖最多剩余待覆盖城市的路线,若多条路线覆盖数相同,优先选本身覆盖城市总数更多的路线
  3. 把选中的路线加入结果列表,将它覆盖的城市从剩余待覆盖集合中移除
  4. 重复步骤2-3,直到剩余待覆盖城市为空,或者没有路线能再新增覆盖任何待覆盖城市为止
参考Java实现(贪心版本)
import java.util.*;

class RouteWrapper {
    List<String> route;
    Set<String> coverCities;

    public RouteWrapper(List<String> route) {
        this.route = route;
        this.coverCities = new HashSet<>(route);
    }
}

public class RouteGroupProblem {
    public static void main(String[] args){
        List<List<String>> allRoutes = new ArrayList<>();
        allRoutes.add(List.of("Newyork","Washington","Los Angeles","Chicago"));
        allRoutes.add(List.of("Newyork","Houston","Alaska"));
        allRoutes.add(List.of("Newyork","Dallas"));
        allRoutes.add(List.of("Newyork","Houston","Washington","Chicago","Los Angeles","Alaska"));
        allRoutes.add(List.of("Newyork","Alaska"));
        allRoutes.add(List.of("Newyork","Chicago"));
        allRoutes.add(List.of("Newyork","Los Angeles"));
        Set<String> cities = new HashSet<>(List.of("Newyork","Houston","Washington","Chicago","Los Angeles","Alaska", "Dallas"));

        List<List<String>> result = findBestRoute(allRoutes, cities);
        for (List<String> route : result) {
            System.out.println(String.join(" -> ", route));
        }
    }

    private static List<List<String>> findBestRoute(List<List<String>> allRoutes, Set<String> targetCities) {
        List<RouteWrapper> wrappers = new ArrayList<>();
        // 预处理路线
        for (List<String> route : allRoutes) {
            RouteWrapper wrapper = new RouteWrapper(route);
            // 过滤完全无效的路线
            boolean isValid = false;
            for (String city : wrapper.coverCities) {
                if (targetCities.contains(city)) {
                    isValid = true;
                    break;
                }
            }
            if (!isValid) continue;
            // 剔除冗余路线
            boolean isRedundant = false;
            Iterator<RouteWrapper> it = wrappers.iterator();
            while (it.hasNext()) {
                RouteWrapper exist = it.next();
                // 已有路线完全覆盖当前路线,当前路线冗余
                if (exist.coverCities.containsAll(wrapper.coverCities)) {
                    isRedundant = true;
                    break;
                }
                // 当前路线完全覆盖已有路线,已有路线冗余
                if (wrapper.coverCities.containsAll(exist.coverCities)) {
                    it.remove();
                }
            }
            if (!isRedundant) {
                wrappers.add(wrapper);
            }
        }

        List<List<String>> result = new ArrayList<>();
        Set<String> remainingTarget = new HashSet<>(targetCities);

        while (!remainingTarget.isEmpty() && !wrappers.isEmpty()) {
            RouteWrapper bestRoute = null;
            int maxCoverCount = -1;
            // 选当前收益最高的路线
            for (RouteWrapper wrapper : wrappers) {
                int coverCount = 0;
                for (String city : wrapper.coverCities) {
                    if (remainingTarget.contains(city)) {
                        coverCount++;
                    }
                }
                if (coverCount > maxCoverCount) {
                    maxCoverCount = coverCount;
                    bestRoute = wrapper;
                }
            }
            // 没有能新增覆盖的路线,退出
            if (maxCoverCount == 0) break;
            // 更新结果和待覆盖集合
            result.add(bestRoute.route);
            remainingTarget.removeAll(bestRoute.coverCities);
            wrappers.remove(bestRoute);
        }
        return result;
    }
}

上述实现可直接跑通你给出的三个测试用例,输出和示例完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 00:00:00