基于Or-Tools的指派问题建模求解(PythonAPI)

news2024/11/23 13:18:39

基于Or-Tools的指派问题建模求解(PythonAPI)

  • 指派问题(又称为分配问题,assignment problem)
  • 基于Or-Tools的指派问题建模求解(PythonAPI)
    • 导入pywraplp库
    • 数据准备
    • 声明MIP求解器
    • 初始化决策变量
    • 初始化约束条件
    • 目标函数
    • 调用求解器
    • 打印结果
    • 求解结果
    • 完整代码

指派问题(又称为分配问题,assignment problem)

指派问题(又称为分配问题,assignment problem)可以抽象概括为:将n个任务(或物品)分配给m个员工(或背包)的问题。其中,最简单的平衡指派模型是指任务数量和员工数量相等的情形。然而,现实生活中的问题大多是任务数量大于员工数量且员工能力有限的广义指派问题(generalized assignment problem,GAP)。GAP是经典的组合优化问题,许多领域的容量约束问题都可以被抽象为GAP进行求解,如机器调度问题、有容量约束的设施选址问题、供应链问题及车辆路径问题等。

广义指派模型
GAP问题可以描述为:将n个相互独立的任务分配给m个员工,一个任务智能由一个员工来完成,一个员工可以完成多项任务,但员工完成任务的总时间不得超过给定限制。

对于 i = 1 , . . . , m i=1,...,m i=1,...,m j = 1 , . . . , n j=1,...,n j=1,...,n,定义0-1决策变量x_ij=1,表示任务j分配给员工i。令 I = { i ∣ i = 1 , ⋯   , m } I=\{i | i=1,\cdots,m\} I={ii=1,,m}为员工集合, J = { j ∣ j = 1 , ⋯   , n } J=\{j | j=1, \cdots, n\} J={jj=1,,n}为任务集合, b i b_i bi表示员工自身的工作时长限制, r i j r_{ij} rij表示员工 i i i完成任务 j j j需要的时长, c i j c_{ij} cij表示员工 i i i完成任务 j j j所消耗的资源或产生的收益。最终目标函数为成本最小或收益最大,则GAP可表述为
max ⁡ 或   min ⁡ ∑ i ∈ I ∑ j ∈ J c i j x i j \begin{align} \max 或 \,\min \sum_{i \in I} \sum_{j \in J} c_{ij}x_{ij} \end{align} maxminiIjJcijxij s . t . s.t. s.t.
∑ j ∈ J r i j x i j ≤ b i , ∀ i ∈ I ∑ i ∈ I x i j = 1 , ∀ j ∈ J x i j ∈ { 0 , 1 } , ∀ j ∈ J \begin{align} \sum_{j \in J} r_{ij}x_{ij} \leq b_i, \quad \forall i \in I \\ \sum_{i \in I}x_{ij}=1, \quad \forall j \in J \\ x_{ij} \in \{0,1\}, \quad \forall j \in J \end{align} jJrijxijbi,iIiIxij=1,jJxij{0,1},jJ
具有上述形式的整数规划模型被称为广义指派模型。

基于Or-Tools的指派问题建模求解(PythonAPI)

在这个例子中,有5个工人(编号0-4)和4个任务(编号0-3),将工人分配给任务的成本如下表所示:

目标为最小化总成本,约束为每个工人最多完成一个任务,每个任务只能由一个工人完成。这个问题中由于工人数多于任务数,因此有一个工人分不到任务。

导入pywraplp库

from ortools.linear_solver import pywraplp

数据准备

costs = [
    [90, 80, 75, 70],
    [35, 85, 55, 65],
    [125, 95, 90, 95],
    [45, 110, 95, 115],
    [50, 100, 90, 100],
]
num_workers = len(costs)  # 工人数量
num_tasks = len(costs[0])  # 任务数量

声明MIP求解器

solver = pywraplp.Solver.CreateSolver("SCIP")

初始化决策变量

x = {}
for i in range(num_workers):
    for j in range(num_tasks):
        x[i, j] = solver.IntVar(0, 1, "")

初始化约束条件

# 每个员工至多完成一项任务
for i in range(num_workers):
    solver.Add(solver.Sum([x[i, j] for j in range(num_tasks)]) <= 1)

# 每项任务只能由一个员工完成
for j in range(num_tasks):
    solver.Add(solver.Sum([x[i, j] for i in range(num_workers)]) == 1)

目标函数

objective_terms = []
for i in range(num_workers):
    for j in range(num_tasks):
        objective_terms.append(costs[i][j] * x[i, j])
solver.Minimize(solver.Sum(objective_terms))

调用求解器

status = solver.Solve()

打印结果

if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:
    print(f"Total cost = {solver.Objective().Value()}\n")
    for i in range(num_workers):
        for j in range(num_tasks):
            # Test if x[i,j] is 1 (with tolerance for floating point arithmetic).
            if x[i, j].solution_value() > 0.5:
                print(f"Worker {i} assigned to task {j}." + f" Cost: {costs[i][j]}")
else:
    print("No solution found.")
    

求解结果

Total cost = 265.0
Worker 0 assigned to task 3. Cost = 70
Worker 1 assigned to task 2. Cost = 55
Worker 2 assigned to task 1. Cost = 95
Worker 3 assigned to task 0. Cost = 45

完整代码

from ortools.linear_solver import pywraplp


def main():
    # Data
    costs = [
        [90, 80, 75, 70],
        [35, 85, 55, 65],
        [125, 95, 90, 95],
        [45, 110, 95, 115],
        [50, 100, 90, 100],
    ]
    num_workers = len(costs)
    num_tasks = len(costs[0])

    # Solver
    # Create the mip solver with the SCIP backend.
    solver = pywraplp.Solver.CreateSolver("SCIP")

    if not solver:
        return

    # Variables
    # x[i, j] is an array of 0-1 variables, which will be 1
    # if worker i is assigned to task j.
    x = {}
    for i in range(num_workers):
        for j in range(num_tasks):
            x[i, j] = solver.IntVar(0, 1, "")

    # Constraints
    # Each worker is assigned to at most 1 task.
    for i in range(num_workers):
        solver.Add(solver.Sum([x[i, j] for j in range(num_tasks)]) <= 1)

    # Each task is assigned to exactly one worker.
    for j in range(num_tasks):
        solver.Add(solver.Sum([x[i, j] for i in range(num_workers)]) == 1)

    # Objective
    objective_terms = []
    for i in range(num_workers):
        for j in range(num_tasks):
            objective_terms.append(costs[i][j] * x[i, j])
    solver.Minimize(solver.Sum(objective_terms))

    # Solve
    status = solver.Solve()

    # Print solution.
    if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:
        print(f"Total cost = {solver.Objective().Value()}\n")
        for i in range(num_workers):
            for j in range(num_tasks):
                # Test if x[i,j] is 1 (with tolerance for floating point arithmetic).
                if x[i, j].solution_value() > 0.5:
                    print(f"Worker {i} assigned to task {j}." + f" Cost: {costs[i][j]}")
    else:
        print("No solution found.")


if __name__ == "__main__":
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1145263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自然语言处理 (NLP) 简介

自然语言处理 &#xff08;Natural Language Processing NLP&#xff09; 简介 本课程是关于NLP 101的4部分系列中的第1部分&#xff1a; 自然语言处理导论&#xff08;今天的教程&#xff09;BagofWords模型简介Word2Vec&#xff1a;自然语言处理中嵌入的研究BagofWords与Wo…

3年轻量:腾讯云轻量2核2G4M应用服务器366三年!

腾讯云轻量应用服务器三年特价&#xff0c;3年轻量2核2G4M服务器&#xff0c;2023双十一优惠价格366元三年&#xff0c;自带4M公网带宽&#xff0c;下载速度可达512KB/秒&#xff0c;300GB月流量&#xff0c;50GB SSD盘系统盘&#xff0c;阿腾云atengyun.com分享腾讯云轻量2核2…

apk反编译修改教程系列-----修改apk中的图片 任意更换apk桌面图片【三】

往期教程&#xff1a; apk反编译修改教程系列-----修改apk应用名称 任意修改名称 签名【一】 apk反编译修改教程系列-----任意修改apk版本号 版本名 防止自动更新【二】 这次实例演示下如何更换apk安装后的桌面图标图片。其实这个步骤前面我有一个教程贴。这次针对步骤做个补…

C++初阶-类和对象(中)1

类和对象&#xff08;中&#xff09;1 一、类的6个默认成员函数二、构造函数概念特性 三、析构函数概念特性 四、拷贝构造函数概念特征 一、类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何…

ASP.NET WebApi 极简依赖注入

文章目录 环境服务类启动项注入使用依赖注入的优点 环境 .NET Core 7.0ASP.NET CoreVisual Studio 2022 服务类 public class T_TempService {public T_TempService(){}public void Test(){}}启动项注入 #region 依赖注入 builder.Services.AddTransient<T_TempService&g…

【LeetCode力扣】189 53 轮转数组 | 最大子数组和

目录 1、189. 轮转数组 1.1、题目介绍 1.2、解题思路 2、53. 最大子数组和 2.1、题目介绍 2.2、解题思路 1、189. 轮转数组 1.1、题目介绍 原题链接&#xff1a;189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; ​ 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3输…

Android数据对象序列化原理与应用

序列化与反序列化 序列化是将对象转换为可以存储或传输的格式的过程。在计算机科学中&#xff0c;对象通常是指内存中的数据结构&#xff0c;如数组、列表、字典等。通过序列化&#xff0c;可以将这些对象转换为字节流或文本格式&#xff0c;以便在不同的系统之间进行传输或存…

ChineseChess4 2023.10.27

中国象棋残局&#xff1a;黑双卒压境&#xff0c;如何破黑中心卒 要么一将黑棋死棋&#xff0c;要么想法子把黑中卒干掉&#xff0c;而且干掉中卒&#xff0c;基本要想用车去抽&#xff0c;也不知道棋局有问题呢&#xff0c;还是怎么回事&#xff0c;没想到。 中国象棋残局模拟…

重要环节不可忽视,CSS性能优化引领用户体验!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、前…

【驱动开发】基于GPIO子系统编写LED驱动,编写应用程序进行测试设置定时器,5秒钟打印一次hello world

基于GPIO子系统编写LED驱动&#xff0c;编写应用程序进行测试&#xff0c;设置定时器&#xff0c;5秒钟打印一次hello world 驱动程序&#xff1a; #include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.…

Tensorflow2 中模型训练标签顺序和预测结果标签顺序不一致问题解决办法

本篇文章将详细介绍Tensorflow2.x中模型训练标签顺序和预测结果标签顺序不一致问题&#xff0c;这个问题如果考虑不周&#xff0c;或者标签顺序没有控制好的情况下会出现预测结果精度极其不准确的情况。 训练数据集的结构&#xff1a;数据集有超过10的类别数&#xff0c;这里包…

全网最详细的大数据架构搭建配置及说明文档

版本兼容 JDK1.8.0_211ZooKeeper3.4.14Hadoop3.2.1Hive3.1.2HBase2.2.1Scala2.13.1Spark2.4.4MySQL5.7.28 基本配置 修改ip和主机名 主机名IP地址JavaZookeeperHadoopHiveHBaseSparkMySQLhadoop192.168.137.201√√√√√√slave1192.168.137.202√√√√√√slave2192.168…

如何在《倩女幽魂》游戏中使用搭建工具

如何在《倩女幽魂》游戏中使用搭建工具 S5 一键搭建脚本 进行 游戏礼包销售。 首先&#xff0c;定义在《倩女幽魂》游戏中使用搭建工具 S5 一键搭建脚本 进行 游戏礼包销售&#xff0c;需要完成以下几个步骤&#xff1a; 准备工作&#xff1a;确保您已经安装了华科云商软件&am…

Vite+Vue3项目全局引入scss文件

前言 Sass 是世界上最成熟、最稳定、最强大的专业级CSS扩展语言&#xff01;在日常项目开发过程中使用非常广泛&#xff0c;今天主要讲一下 ViteVue3 项目中该如何全局引入 scss 文件&#xff0c;引入混合 mixin 文件的不同配置。捎带说一下 Vue2 中的引入方式做一下简单的对比…

力扣:143. 重排链表(Python3)

题目&#xff1a; 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进…

8通道模数转换AD7091驱动代码SPI接口ADC,verilog

名称&#xff1a;8通道模数转换AD7091驱动代码 软件&#xff1a;QuartusII 语言&#xff1a;Verilog 代码功能&#xff1a; 使用verilog代码设计AD7091R-8驱动代码 控制接口为SPI接口&#xff0c;实现8通道模数转换&#xff0c;输出8通道数字信号。 FPGA代码Verilog/VHDL代码…

JS问题:如何实现文本一键复制和长按复制功能?

前端功能问题系列文章&#xff0c;点击上方合集↑ 序言 大家好&#xff0c;我是大澈&#xff01; 本文约2000字&#xff0c;整篇阅读大约需要4分钟。 本文主要内容分三部分&#xff0c;第一部分是需求分析&#xff0c;第二部分是实现步骤&#xff0c;第三部分是问题详解。 …

学习视觉CV Transformer (2)--Transformer原理及代码分析

下面结合代码和原理进行深入分析Transformer原理。 2 Transformer深入分析 对于CV初学者来说&#xff0c;其实只需要理解Q K V 的含义和注意力机制的三个计算步骤&#xff1a; Q 和所有 K 计算相似性&#xff1b;对相似性采用 Softmax 转化为概率分布&#xff1b;将概率分布…

DCL 单例模式设计为什么需要 volatile 修饰实例对象

DCL 问题&#xff0c;是在基于双重检查锁设计下的单例模式中&#xff0c;存在不 完整对象的问题。而这个不完整对象的本质&#xff0c;是因为指令重排序导致的。 public class DCLExample {private static DCLExample instance;public static DCLExample getInstance(){if (ins…

2021年06月 Python(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 执行下列代码后&#xff0c;运行结果是&#xff1f; seq[hello,good,morning] s*.join(seq) print(s)A: hello*good*m…