混合贪心算法求解地铁线路调度

一、问题描述

城市轨道交通的繁荣发展,带来了车辆资源需求的日益增加。如何兼顾运营服务水平和运营成本,以最少的车底优质地完成运输任务成为一大严峻问题。本题在后续的描述中将由多辆动车和拖车组合而成的车组称为车底。在日常的运营组织中,车底运用计划指导着所有的车底有序的完成运输任务,是运输计划中非常重要一项。较多的车底运用数可以从容的面对各种客流压力,深受乘客的欢迎却往往不能发挥车底的运输能力,导致运营成本骤升;而车底过少又极易引起车底超负荷运转,缩短设备寿命,面对大客流情况还有可能出现运营紊乱,乘客体验差。因此,车底运用计划对协调运营质量和运营成本意义重大。基于列车运行时刻表,结合列车车底数量、车辆段或停车场(以下统称为车场)的数量、车场的分布状况及容纳能力等,对每一车底在何时何地驶出车场、担当哪些车次以及返回车场作出合理的安排;同时,根据车底检修相关规程,对每一车底的检修时间、检修地点、检修级别等作出具体安排,保证安全、高效、有序的完成日常运营任务。

现在假设有一个地铁运营线,该线网由 20 座车站构成, 本线路全周转时间:120min30s;共有 35 组,停车场的存车能力为 25,车辆段的存车能力为 20;列车运行间隔:早高峰 3min(7点到9点),平峰 8min,晚高峰3min25s(17点到20点),其中,大交路 1-20,小交路1-15,早晚高峰的追踪间隔均指小交路的追踪间隔;列车通过 9 号车站进出车辆段,出入段时间为 2min40s;1,15,20 号车站具备折返能力,其最短折返时间分别为:6min、4min30s、4min30s;1号车
站连接停车场,停车场的出入时间 2min。
在这里插入图片描述
简而言之,要求就是使用最少的车底完成所有车次的牵引计划,同时每辆车的牵引时长要尽量均衡。

二、数据介绍

车次数据分位上行车次和下行车次,上行车次表示从编号较大的站到编号较小的站,下行车次从编号较小的站到编号较大的站,流入从1到20是下行车次,从20到1是上行车次。每天的上、下行车次数各为244。
上行车次
下行车次

三、算法求解

在这一小节中主要介绍两部分内容,第一部分内容是如何获得使用车底尽量少的车底牵引方案,第二部分是如何在保证车底数量不变的前提下,使得每个车底的牵引时间更加均衡。

3.1 车底数量求解

贪心算法
对于此类问题,一个直观的想法采用贪心的策略,对于对于每一个车底,都使得牵引尽量多的车次,直到所有的车次完成牵引,这个时候用到的车底数量就是贪心算法得到的最少车底数量,基本算法流程如下:

step1、初始化使用车底集合为C={},当前车底牵引车次集合D={},剩余车次集合P为上下行全量车次;
step2、按照时空接续关系生成所有可行车次集合,如果可行车次为空,转step4;
step3、随机选择可行接续车次作为车底即将牵引的车次d,D=D+d,P=P-d,转step2;
step4 、如果剩余车底集合P为空,转step6,否则转step5;
step5、更新使用车底集合C,新增车底,转step2;
step6、输出车底牵引计划;
step7、结束。

其中,step2中的时空接续关系是指车底前后牵引的两趟车次在时间和空间上都必须是能够衔接的,在空间上前车的终点站必须是后撤的起点站,在时间上前车的到达时间必须早于后车的出发时间,且时间间隔要满足特定要求。

贪心算法最终结果为使用车底数量41,由于step3中随机选择当前车底的可行车次,导致每个车底的牵引车辆数相对有限,考虑结合整数规划模型来获得当前车底的最优解决方案。

混合贪心算法
step1、初始化使用车底集合为C={},当前车底牵引车次集合D={},剩余车次集合P为上下行全量车次;
step2、计算剩余所有车次的前序车次数量和后续车次数量;
step3、按照车辆的前序车次数和后续车次数进行排序;
step4、将前序车次数和后续车次数量最少的车辆作为必选车次,建立整数规划模型,获取最优路径,最大化彻底服务车次数;
step5、将车底牵引计划添加到车底集合中,更新剩余车次,如果所有列车牵引完成,转step6,否则转step2;
step6、输出车底牵引计划;
step7、结束。

混合贪心算法最终使用的车底数量为36,相比于贪心算法,混合贪心算法主要在两个方面有所改进。一个是优先选择车前序和后续车次少的车次进行分配,这是由于到了算法后期,这样的车次往往一个车次就要完全占据一个车底。另外一个改进的点是采用整数规划,能够真正意义上获取每个车底当前的最优选择。
在这里插入图片描述
从上述甘特图中也可以明显看出贪心策略的一些特征,排序靠前的车底,由于有比较大的选择空间,牵引路径都比较长,牵引负载比较大,排序靠后的车底,由于选择空间急剧收缩,往往一个车底只能服务一两趟车次。

3.2 负载均衡调整

由于贪心策略产生的结果会出现负载极度不均衡的情况,考虑采用局部调整策略对产生的方案进行调整。调整的思路很简单,将负载比较高的车底服务的车次重新分配给负载比较低的车底即可,其对应的基本流程如下:
在这里插入图片描述
调整过后的结果如下,从图上可以看出来调整之后的结果变得更加均衡了。在这里插入图片描述

四、代码实现

4.1 贪心算法
def get_path(all_trains,from_trains,to_trains):
    used_trains=[]
    all_path=[]
    cnt=0

    max_length=22
    max_num=[randint(18,22) for i in range(1000)]
    
    
    while len(set(used_trains))!=len(all_trains):
        route_length=min(max_length,max_num[cnt])
        for i in range(route_length,0,-1):
            result=solver_route(all_trains,from_trains,to_trains,used_trains,i)
            if result:
                break
            else:
                max_length=i-1

        used_trains+=result
        all_path.append(result)
        cnt+=1
    return all_path
4.2 整数规划
def solver_route(all_trains,from_trains,to_trains,used_trains,route_length):
    train_num=len(all_trains)


    # 创建模型
    model = gp.Model('train_scheduling')
    
    # 数据处理
    new_from_trains=deepcopy(from_trains)
    new_to_trains=deepcopy(to_trains)
    for train in all_trains:
        new_from_trains[train]=list(set(new_from_trains[train])-set(used_trains))
        new_to_trains[train]=list(set(new_to_trains[train])-set(used_trains))
    
    io_num={}
    for i in range(len(all_trains)):
        train=all_trains[i]
        io_num[i]=len(new_from_trains[train])+len(new_to_trains[train]) 
        
    dff=pd.DataFrame(io_num.items(),columns=['key','value'])
    sort_trains=dff.sort_values(by=['value'],ascending=False)['key'].values
    
    fix_train=-1
    for train in sort_trains:
        if not train in used_trains:
            fix_train=train
            break
    

    # 是否将站点i放置在位置j
    x = {}
    for i in range(train_num):
        for j in range(route_length):
            x[i,j] = model.addVar(vtype=GRB.BINARY, name=f'x_{i}_{j}')



    # 目标函数
    obj=0
    for i in range(train_num):
        for j in range(route_length):
            obj+=io_num[i]*x[i,j]
    model.setObjective(obj,GRB.MINIMIZE)


    # 每个位置最多有一个节点
    for j in range(route_length):
        expr=0
        for i in range(train_num):
            expr+=x[i,j]
        model.addConstr(expr==1)



    # 节点之间要有连关系
    for j in range(route_length-1):
        for i  in range(train_num):
            expr=0
            train=all_trains[i]
            for ii in from_trains[train]:
                expr+=x[ii,j]
            model.addConstr(expr>=x[i,j+1])

    # 遍历过的车次不再选择
    for i in used_trains:
        expr=0
        for j in range(route_length):
            expr+=x[i,j]
        model.addConstr(expr<=0)
        
    # fix train一定要满足
    expr=0
    for j in range(route_length):
        expr+=x[fix_train,j]
    model.addConstr(expr==1)



    # 求解
    model.setParam('OutputFlag', 0)
    model.setParam(GRB.Param.TimeLimit, 60)
    model.optimize()

    # 检查求解器状态
    status = model.Status
    if status == GRB.INFEASIBLE:
        return []
    else:
        return get_result(x,train_num,route_length)
局部调整
paths=[]
for idx,row in result.iterrows():
    path=eval(row[0])
    paths.append(path)
    
for i in range(len(paths)):
    path=paths[i]
    remove_trains=[]
    path_duration=get_path_duration(path)
    print(path_duration)
    for train in path:
        if path_duration<=avg:
            break
        for j in range(i+1,len(paths)):
            add_path=paths[j]
            add_path_duration=get_path_duration(add_path)
            if add_path_duration>avg:
                continue
            idx=get_insert_index(train,add_path)
            if idx>0:
                add_path.insert(idx,train)
                remove_trains.append(train)
                path_duration-=(train_info.end_time-train_info.start_time)
                break
    for train in remove_trains:
        paths[i].remove(train)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单链表(C语言详细版)

1. 链表的概念及结构 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表的结构跟火车车厢相似&#xff0c;淡季时车次的车厢会相应减少&#xff0c;旺季时车次的车厢会额外增加几节。…

elasticsearch SQL:在Elasticsearch中启用和使用SQL功能

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

苍穹外卖--导入分类模块功能代码

把各层代码拷贝到所需文件夹下&#xff0c; 进行编译 在运行 提交和推送仓库

C++:C++入门基础|命名空间|输入输出

欢迎来到HarperLee的学习笔记&#xff01; 博主主页传送门&#xff1a; HarperLee的博客主页! 想要一起进步的uu来后台哦&#xff01; 一、什么是C? 在此之前&#xff0c;我们所学习的C语言是一种结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&a…

【STM32】MDK的编译过程及文件类型全解

1.编译过程简介 编译&#xff1a;MDK软件使用的编译器是armcc和armasm&#xff0c; 它们根据每个c/c和汇编源文件编译成对应的以“.o”为后缀名的对象文件(Object Code&#xff0c;也称目标文件)&#xff0c; 其内容主要是从源文件编译得到的机器码&#xff0c;包含了代码、数据…

怎么压缩ppt?这几种压缩方法大家都在用!

怎么压缩ppt&#xff1f;当我们沉浸在PPT创作的海洋中&#xff0c;每一个精心的布局、每一个动人的动画&#xff0c;都仿佛是我们心血的结晶&#xff0c;然而&#xff0c;随着我们不断雕琢&#xff0c;PPT文件的大小也在悄然增长&#xff0c;如同一只隐形的巨兽&#xff0c;在不…

无线充电宝哪个牌子好?绿联、西圣、小米充电宝测评对比!

随着科技的不断进步和智能设备的普及&#xff0c;无线充电宝逐渐成为了现代人生活中的必需品。它们不仅方便了我们的日常充电需求&#xff0c;更减少了线缆的束缚&#xff0c;提高了使用的便捷性。在众多品牌中&#xff0c;绿联、西圣和小米作为市场上广受好评的无线充电宝品牌…

Windows下载、配置Java JDK开发环境的方法

本文介绍在Windows电脑中&#xff0c;安装JDK&#xff08;Java Development Kit&#xff09;&#xff0c;也就是Java开发工具包的详细方法。 JDK是Java软件开发的基础&#xff0c;由Oracle公司提供&#xff0c;用于构建在Java平台上运行的应用程序与组件等&#xff1b;其已经包…

【windows】安装抓包工具Burp Suite 2024激活汉化

前言 在项目即将上线阶段&#xff0c;迈入生产环境之际&#xff0c;确保其安全性成为我们不可忽视的首要任务。为筑起一道坚不可摧的安全防线&#xff0c;我们借助业界公认的网络安全利器——Burp Suite&#xff0c;我们将展开一场全面的安全测试&#xff0c;旨在探查并消除任…

旗晟机器人AI智能算法有哪些?

在当今迅猛发展的工业4.0时代&#xff0c;智能制造和自动化运维已然成为工业发展至关重要的核心驱动力。伴随技术的持续进步&#xff0c;工业场景中的运维巡检已不再单纯地依赖于传统的人工运维方式&#xff0c;而是愈发多地融入了智能化的元素&#xff0c;其中智能巡检运维系统…

数据库MySQL---基础篇

存储和管理数据的仓库 MySQL概述 数据库相关概念 数据库&#xff08;DataBase&#xff09;---数据存储的仓库&#xff0c;数据是有组织的进行存储 数据库管理系统&#xff08;DBMS&#xff09;-----操纵和管理数据库的大型软件 SQL----操作关系型数据库的编程语言&#xff…

文华财经盘立方多空变色波段趋势线指标公式源码

文华财经盘立方多空变色波段趋势线指标公式源码&#xff1a; N1:20; N2:ROUND(N1/2,1); N3:ROUND(SQRT(N1),1); N4:2*EMA2(C,N2)-EMA2(C,N1); 尊重市场:EMA2(N4,N3),COLORRED,LINETHICK2; 尊重市场1:IF(尊重市场<REF(尊重市场,1), 尊重市场,NULL),COLORGREEN,LINETHIC…

gitlab-runner安装部署CI/CD

手动安装 卸载旧版&#xff1a; gitlab-runner --version gitlab-runner stop yum remove gitlab-runner下载gitlab对应版本的runner # https://docs.gitlab.com/runner/install/bleeding-edge.html#download-any-other-tagged-releasecurl -L --output /usr/bin/gitlab-run…

打开IDEA,程序员思考的永远只有两件事!!!

微信公众号&#xff1a;牛奶 Yoka 的小屋 有任何问题。欢迎来撩~ 最近更新&#xff1a;2024/07/09 [大家好&#xff0c;我是牛奶。] 当年面试时背了很多八股文&#xff0c;但在日渐重复的机械工作中&#xff08;产品业务开发&#xff09;&#xff0c;计算机网络、操作系统、算…

leetcode:LCR 018. 验证回文串(python3解法)

难度&#xff1a;简单 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 本题中&#xff0c;将空字符串定义为有效的 回文串 。 示例 1: 输入: s "A man, a plan, a canal: Panama" 输出: t…

编辑器 goland 和 visual studio code

goland 编辑器做的真是太好了&#xff0c;面向 go 代码的定制设计&#xff0c;但它是收费软件&#xff0c;价格还贵的超出了自己的经济能力范围。有时候想打几行代码&#xff0c;却没有趁手的兵器&#xff0c;真是难受。但求助免费破解版吧&#xff0c;又需要关注公众号&#x…

Lab1 论文 MapReduce

目录 &#x1f339;前言 &#x1f985;2 Programming Model &#x1f33c;2.1 Example &#x1f33c;2.2 Types &#x1f33c;2.3 More Examples &#x1f985;3 Implementation(实现) &#x1f33c;3.1 ~ 3.3 &#x1f33c;3.4 ~ 3.6 &#x1f985;4 Refinemen…

Java-Redis-Clickhouse-Jenkins-MybatisPlus-Zookeeper-vscode-Docker-jdbc-xxljob

文章目录 Clickhouse基础实操windows docker desktop 下载clickhousespringboot项目配置clickhouse Redis谈下你对Redis的了解&#xff1f;Redis一般都有哪些使用的场景&#xff1f;Redis有哪些常见的功能&#xff1f;Redis支持的数据类型有哪些&#xff1f;Redis为什么这么快…

爬虫怎么实现抓取的

1.4爬虫工程师常用的库通过图1-3我们了解到&#xff0c;爬虫程序的完整链条包括整理需求、分析目标、发出网络请求、文本解析、数据入库和数据出库。其中与代码紧密相关的有&#xff1a;发出网络请求、文本解析、数据入库和数据出库&#xff0c;接下来我们将学习不同阶段中爬虫…

Proxmox VE 8虚拟机直通USB磁盘

作者&#xff1a;田逸&#xff08;fromyz&#xff09; 今天有个兄弟发消息&#xff0c;咨询怎么让插在服务器上的U盾被Proxmox VE上的虚拟机识别。在很久很久以前&#xff0c;我尝试过在Proxmox VE 5以前的版本创建windows虚拟机&#xff0c;并把插在Proxmox VE宿主机上的银行U…