0

0

Google OR-Tools 中实现节点位置依赖的动态路径成本建模

碧海醫心

碧海醫心

发布时间:2026-01-07 13:53:00

|

870人浏览过

|

来源于php中文网

原创

Google OR-Tools 中实现节点位置依赖的动态路径成本建模

本文介绍如何在 or-tools 的 vrp 求解器中建模「同一节点在路径中不同位置(中间 or 终点)具有不同成本」的场景,通过节点复制、活动变量约束与惩罚型 disjunction 技术实现动态成本嵌入。

在标准车辆路径问题(VRP)中,节点成本通常被建模为边权重(如 distance_matrix[i][j])或固定服务成本,但 Google OR-Tools 原生不支持「节点成本随其在路径中的逻辑位置(如是否为最后一个非仓库节点)动态变化」的直接表达。上述问题中,每个客户节点 i 有两个成本:part(作为中间节点时的开销)和 final(作为该车辆路径的最终客户时的开销),而仓库(depot)始终为起点和终点(索引 0)。目标是最小化路径中所有“被访问且承担对应角色”的节点成本之和。

核心思路是将语义上“一个节点两种角色”转化为物理上“两个独立节点”,再通过求解器约束强制互斥选择与角色绑定:

✅ 实现步骤详解

  1. 节点复制(Node Duplication)
    对每个客户节点 i ∈ {1, 2, ..., n},创建两个索引:

    • regular_i:代表“作为中间节点出现”(即路径中非末尾客户)
    • final_i:代表“作为该车辆路径最后一个客户出现”

    Depot(索引 0)保持唯一,但需特殊处理:它既是起点,也作为每条路径的显式终点(0 → ... → final_i → 0),但 final_i → 0 这段弧的成本设为 0,不计入目标函数。

    Woy AI
    Woy AI

    通过 Woy.ai AI 导航站发现 2024 年顶尖的 AI 工具!

    下载
  2. 约束节点后继关系(NextVar Control)
    使用 routing.NextVar(index) 显式限制每个节点的合法后继:

    • regular_i 的后继只能是其他 regular_j 或 final_j(不能是 depot),确保它不会成为路径终点;
    • final_i 的后继只能是 depot(0)或 -1(表示被丢弃),即:routing.AddToAssignment(routing.NextVar(final_i) == 0) 或通过 AllowedValues 限定。
  3. 互斥访问约束(Disjunction / ActiveVar Sum)
    防止同一客户被重复访问(如既选 regular_1 又选 final_1):

    # 确保 regular_i 和 final_i 至多被激活一个
    routing.AddVariableMinimizedByFinalizer(routing.ActiveVar(regular_i))
    routing.AddVariableMinimizedByFinalizer(routing.ActiveVar(final_i))
    routing.solver().Add(
        routing.ActiveVar(regular_i) + routing.ActiveVar(final_i) <= 1
    )
  4. 动态成本嵌入(Penalty-based Objective)
    利用 AddDisjunction() 引入软约束,将“未被选中”转化为目标函数中的显式惩罚:

    • 对 regular_i:若未被激活(即未作为中间节点使用),则需支付 part[i] 成本(因客户必须被服务,未被中间服务就只能由 final 承担)→ 但更合理的是:对 final_i 设置 part[i] 的惩罚,表示“若不选 final_i,则必须以 part 方式服务,但此时它无法成为终点” —— 实际建模中,我们反向设计:
      • 为 final_i 添加 disjunction,惩罚值为 part[i]:若 final_i 被丢弃(ActiveVar=0),则加罚 part[i](意味着该客户只能以“中间”方式服务,但需保证其确实在某路径中);
      • 为 regular_i 添加 disjunction,惩罚值为 final[i]:若 regular_i 被丢弃,加罚 final[i](意味着它必须作为终点被服务)。
    • 最终目标函数 = 所有被激活节点的 part/final 成本之和 + 所有触发的惩罚项。
  5. Depot 处理技巧
    将 depot(0)同时设为 Start 和 End:

    for vehicle_id in range(num_vehicles):
        routing.Start(vehicle_id)  # = 0
        routing.End(vehicle_id)    # = 0

    并设置 distance_callback(i, 0) = 0 对所有客户 i,使 final_i → 0 不增加成本,仅用于拓扑闭合。

? 示例代码片段(Python + OR-Tools)

from ortools.constraint_solver import pywrapcp, routing_enums_pb2

# 假设 costs = [{"part":0,"final":0}, {"part":2,"final":3}, ...]
n = len(costs) - 1  # 客户数(不含 depot 0)

# 创建路由模型
manager = pywrapcp.RoutingIndexManager(n * 2 + 1, num_vehicles, 0, 0)
routing = pywrapcp.RoutingModel(manager)

# 定义回调:distance from i to j (0 for any -> depot)
def distance_callback(from_index, to_index):
    from_node = manager.IndexToNode(from_index)
    to_node = manager.IndexToNode(to_index)
    if to_node == 0:  # depot
        return 0
    # 实现客户间距离逻辑(此处简化为 0,重点在 node cost)
    return 0

transit_callback_index = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

# --- 关键:添加 dynamic node cost via penalties ---
for i in range(1, n + 1):
    regular_idx = manager.NodeToIndex(i)           # original node i
    final_idx   = manager.NodeToIndex(i + n)       # duplicated final node

    # 1. 互斥:regular_i 和 final_i 至多一个 active
    routing.solver().Add(
        routing.ActiveVar(regular_idx) + routing.ActiveVar(final_idx) <= 1
    )

    # 2. 约束 next:regular_i 不能指向 depot;final_i 只能指向 depot
    routing.AddToAssignment(routing.NextVar(regular_idx) != 0)
    routing.AddToAssignment(routing.NextVar(final_idx) == 0)

    # 3. Disjunction penalties
    # 若 final_i 未被选,则罚 part[i](客户需以 part 方式服务)
    routing.AddDisjunction([final_idx], costs[i]["part"], 1)
    # 若 regular_i 未被选,则罚 final[i](客户需以 final 方式服务)
    routing.AddDisjunction([regular_idx], costs[i]["final"], 1)

# 求解...
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
    routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
)
solution = routing.SolveWithParameters(search_parameters)

⚠️ 注意事项与最佳实践

  • 索引管理务必清晰:建议用字典映射逻辑节点 i 到 regular_idx / final_idx,避免硬编码错误;
  • 惩罚值需足够大:AddDisjunction(penalty) 中的 penalty 应显著大于任何可行路径成本差异,否则求解器可能“故意丢弃节点”来降低总成本(违背服务全覆盖前提);
  • 验证路径结构:解析解时,需识别 final_i 是否被激活,并确认其前驱是否为 regular_j 或其他 final_k(实际应只接 regular 或起始 depot);
  • 性能考量:节点数量翻倍会增加搜索空间,对大规模实例建议结合 LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH 提升鲁棒性。

该方法虽引入额外变量,但完全兼容 OR-Tools 的 CP-SAT 与 RoutingModel 架构,是解决“位置敏感节点成本”问题的成熟工程实践。完整可运行示例见官方 Gist:https://www.php.cn/link/d42e8faa72ba342df9147902bebb0aac

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
github中文官网入口 github中文版官网网页进入
github中文官网入口 github中文版官网网页进入

github中文官网入口https://docs.github.com/zh/get-started,GitHub 是一种基于云的平台,可在其中存储、共享并与他人一起编写代码。 通过将代码存储在GitHub 上的“存储库”中,你可以: “展示或共享”你的工作。 持续“跟踪和管理”对代码的更改。

3762

2026.01.21

http与https有哪些区别
http与https有哪些区别

http与https的区别:1、协议安全性;2、连接方式;3、证书管理;4、连接状态;5、端口号;6、资源消耗;7、兼容性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2863

2024.08.16

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

26

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

68

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

164

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

84

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

113

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

29

2026.03.03

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

79

2026.02.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 4.8万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号