引入:何为流水线问题

有\(n\)个任务,对于每个任务有\(m\)道工序,每个任务的\(m\)道工序必须在不同的m台机器上依次完成才算把这个任务完成,在前\(i-1\)道工序完成后才能去完成第\(i\)道工序。对于每一个任务的每一道工序在每一台机器上需要的时间都是不同的,求最短完成所有任务的时间,也就是最后一个任务的最后一道工序的完成时间。

流水线问题分为可抢先调度和非抢先调度。在现实生活中,某些时候某个任务会因为突发情况而获得较高的优先级,那么我们就会停下正在做的任务,直接开始这个优先级较高的问题,这就是抢先调度。

由于抢先调度和多流水线的情况比较复杂,所以我们在比赛中很难碰见碰见了就意味着你有更多的时间去写剩下的两道题多吼哇,所以我们只研究非抢先调度的双流水线调度问题。

双流水线问题所具有的适合动态规划的性质

假设第一个机器为\(M1\),第二个机器为\(M2\),第\(i\)个任务在第一个机器上所需的时间是\(a_i\),在第二个机器上所需的时间是\(b_i\)。肯定存在某个最优的策略使得\(M2\)接受的任务的先后顺序和\(M1\)接受的任务顺序一模一样。

在最优策略下,\(M1\)肯定是没有空闲时间的,而\(M2\)只有两种状态,一种是空闲的,一种是任务积压着。不管对于那种状态,\(M2\)接受任务的顺序跟\(M1\)保持一致显然是最优的,因为这样会使\(M2\)的空闲时间最少,也就会使最后一个任务的第二道工序更快完成。

我们令\(T\)(\(s\),\(t\))表示当\(M1\)开始处理任务集合\(s\)时,\(M2\)还需要时间\(t\)才能投入使用,最后完成任务集合\(s\)的最快时间。那么对于非抢先调度问题的答案就是\(T\)(\(N\),\(0\))。

假设最优策略选择第\(i\)个任务最先做,显然答案就是\(a_i\)+\(T\)(\(N-\){\(i\)},\(b_i\))。

再推广一点,对于每个\(T\)(\(s\),\(t\)),都满足\(T\)(\(s\),\(t\))=\(min\){\(a_i\)+\(T\)(\(s-\){\(i\)},\(b_i+max\)(\(t-a_i\),0))}。意思就是在\(M2\)还需要\(t\)时间才能投入使用来执行任务集合\(s\)内的任务时,\(M1\)优先执行任务集合\(s\)里的任务,并且选择第\(i\)号任务为集合\(s\)里第一个被执行的任务,所以在执行\(a_i\)时,\(M2\)的等待时间\(t\)自然也会减少,但是就算\(M2\)上的任务清空了也只能等着\(M1\)这边的任务第一道工序加工完才能再次工作,所以后面的等待时间是\(b_i+max\)(\(t-a_i\),\(0\)),而剩下的任务集合就是\(s-\){\(i\)}。

显然这个动态规划是正确的,但是由于任务的数量过多和任务耗时较长,这个方法并不能很好的解决双流水线非抢先调度问题。

算法进化:\(Jhonson\)登场

假设在最优策略下,对于任务集合\(s\),在\(T\)(\(s\),\(t\))的情况下,第一个在\(M1\)上执行的是\(i\)号任务,第二个是\(j\)号。那么\(T\)(\(s\),\(t\))就可以转化成\(a_i+T\)(\(s-\){\(i\)},\(b_i+max\) (\(t-a_i\),\(0\))),再转化成\(a_i+a_j+T\)(\(s-\){i,j},\(t_{ij}\))。

\(t_{ij}=b_j+max\)(\(b_i+max\)(\(t-a_i\),\(0\))\(-a_j\),\(0\)))

在最外层的\(max\)里提出一个\(b_i-a_j\):

\(t_{ij}=b_j+b_i-a_j+max\)(\(max\)(\(t-a_i\),\(0\)),\(a_j-b_i\)))

\(t_{ij}=b_j+b_i-a_j+max\)(\(t-a_i\),\(0\),\(a_j-b_i\))

再提一个\(-a_i\)出来:

\(t_{ij}=b_j+b_i-a_i-a_j+max\)(\(t\),\(a_i\),\(a_i+a_j-b_i\))

那么在最优策略下,先\(i\)后\(j\)和先\(j\)后\(i\)的区别就只能在那个\(max\)里体现出来了。而\(max\)也刚好影响着\(M2\)的空闲时间,也就是最后答案。那么我们把先\(i\)后\(j\)和先\(j\)后\(i\)的\(max\)分别写出来,他们满足下面这个关系:

\[max(t,a_i,a_i+a_j-b_i)\leqslant max(t,a_j,a_i+a_j-b_j)\]

先假设\(t\)为一个极小值,把它的影响抹去,我们化简一下:

\[max(a_i,a_i+a_j-b_i)\leqslant max(a_j,a_i+a_j-b_j)\]

\[a_i+a_j+max(-a_j,-b_i)\leqslant a_i+a_j+max(-a_i,-b_j)\]

见证奇迹的时刻到了!!我们再次化简!

\[max(-a_j,-b_i)\leqslant max(-a_i,-b_j)\]

等价于:

\[min(a_i,b_j)\leqslant min(a_j,b_i)\]

可是,也许最开始\(max\)里的\(t\)消失得不明不白,这个时候我们反着推回去,只需要满足\(min(a_i,b_j)\leqslant min(a_j,b_i)\)的话,对于任意\(t\)也就必然满足\(max(t,a_i,a_i+a_j-b_i)\leqslant max(t,a_j,a_i+a_j-b_j)\)了。所以只需要满足\(min(a_i,b_j)\leqslant min(a_j,b_i)\)就是最优的调度决策。

于是乎,传说中的\(Jhonson\)表达式就出炉了。对于任何双流水线非抢先调度问题的最优解,任意相邻的\(i,j\)都满足\(Jhonson\)表达式,因为任意相邻的\(i,j\)都有这个比较法则和小于号的传递性,所以任意不相邻的\(i,j(i<j)\),也都满足\(Jhonson\)表达式。我们只需要按照这个式子写一个\(cmp\)函数然后\(sort\)所有的任务,就可以在\(nlogn\)的时间复杂度内解决双流水线调度问题了。

浅谈双流水线调度问题以及Jhonson算法的更多相关文章

  1. 浅谈DFS,BFS,IDFS,A*等算法

    搜索是编程的基础,是必须掌握的技能.--王主任 搜索分为盲目搜索和启发搜索 下面列举OI常用的盲目搜索: 1.dijkstra 2.SPFA 3.bfs 4.dfs 5.双向bfs 6.迭代加深搜索( ...

  2. MMORPG战斗系统随笔(二)、浅谈场寻路Flow Field PathFinding算法

    转载请标明出处http://www.cnblogs.com/zblade/ 今天给大家带来一篇游戏中寻路算法的博客.去年,我加入一款RTS的游戏项目,负责开发其中的战斗系统,战斗系统的相关知识,属于游 ...

  3. 【转】浅谈对主成分分析(PCA)算法的理解

    以前对PCA算法有过一段时间的研究,但没整理成文章,最近项目又打算用到PCA算法,故趁热打铁整理下PCA算法的知识.本文观点旨在抛砖引玉,不是权威,更不能尽信,只是本人的一点体会. 主成分分析(PCA ...

  4. 浅谈URLEncoder编码算法

    一.为什么要用URLEncoder 客户端在进行网页请求的时候,网址中可能会包含非ASCII码形式的内容,比如中文. 而直接把中文放到网址中请求是不允许的,所以需要用URLEncoder编码地址, 将 ...

  5. 浅谈Hex编码算法

    一.什么是Hex 将每一个字节表示的十六进制表示的内容,用字符串来显示. 二.作用 将不可见的,复杂的字节数组数据,转换为可显示的字符串数据 类似于Base64编码算法 区别:Base64将三个字节转 ...

  6. 浅谈Base64编码算法

    一.什么是编码解码 编码:利用特定的算法,对原始内容进行处理,生成运算后的内容,形成另一种数据的表现形式,可以根据算法,再还原回来,这种操作称之为编码. 解码:利用编码使用的算法的逆运算,对经过编码的 ...

  7. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  8. 浅谈分词算法(5)基于字的分词方法(bi-LSTM)

    目录 前言 目录 循环神经网络 基于LSTM的分词 Embedding 数据预处理 模型 如何添加用户词典 前言 很早便规划的浅谈分词算法,总共分为了五个部分,想聊聊自己在各种场景中使用到的分词方法做 ...

  9. 浅谈分词算法(4)基于字的分词方法(CRF)

    目录 前言 目录 条件随机场(conditional random field CRF) 核心点 线性链条件随机场 简化形式 CRF分词 CRF VS HMM 代码实现 训练代码 实验结果 参考文献 ...

随机推荐

  1. oschina git服务, 如何生成并部署ssh key

    1.如何生成ssh公钥 你可以按如下命令来生成 sshkey: ssh-keygen -t rsa -C "xxxxx@xxxxx.com" # Generating public ...

  2. [转载] 把Nutch爬虫部署到Hadoop集群上

    http://f.dataguru.cn/thread-240156-1-1.html 软件版本:Nutch 1.7, Hadoop 1.2.1, CentOS 6.5, JDK 1.7 前面的3篇文 ...

  3. Django之CURD插件

    什么是CURD? CURD顾名思义就是create,update,rearch,delete(所谓的增删改查). 当我们接到一个项目的时候,夸夸夸的就写完表结构,然后就一直写增删改查,增删改查,写了一 ...

  4. isinstance/issubclass/type的区别?

    type() 判断某个对象是否是该类创建的,只看一层,如果是继承类,也不会考虑继承类的类型.. Issubclass() 判断该类是否是另一个类的派生类,也就是子类,参数为类. isinstance( ...

  5. Codeforces441C_Valera and Tubes(暴力)

    Valera and Tubes time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  6. bug-2——tab中beforeActivate:在对象活动前触发

    $j("#tabs").tabs({ beforeActivate:function(event,ui){ var ret = apoCheck('${requestScope.a ...

  7. scala actor编程之对象传递

    scala 最吸引人的一点就是actor并发编程了.但是纵观scala官方文档,baidu文档,IBM文档都写的通过字符串传呀传,如果用作actor编程说明当然没有问题.但是在正式开放中,光传字符串就 ...

  8. linux 8 -- 管道组合Shell命令进行系统管理

    二十. 通过管道组合Shell命令获取系统运行数据: 1.  输出当前系统中占用内存最多的5条命令:     #1) 通过ps命令列出当前主机正在运行的所有进程.     #2) 按照第五个字段基于数 ...

  9. C#与数据库连接简单测试

    效果展示   数据库代码 create database OneDb go USE OneDb; GO CREATE TABLE classify --分类表 ( id ,), name ) not ...

  10. sql查询字段是否为空

    sql 查询某字段为空 select * from 表名 where 字段名 is null sql 查询某字段不为空 select * from 表名 where 字段名 is not null s ...