《数据结构、算法与应用C++语言描述》-机器调度-最长处理时间(LPT)-堆应用

机器调度

完整可编译运行代码见:Github::Data-Structures-Algorithms-and-Applications/_28LongestProcessingTime

问题描述

一个工厂具有 m台一模一样的机器。我们有n 个任务需要处理。设作业i的处理时间为 t i t_i ti,这个时间包括把作业放入机器和从机器上取下的时间。所谓调度(schedule)是指按作业在机器上的运行时间分配作业,使得:

  • 一台机器在同一时间内只能处理一个作业。
  • 一个作业不能同时在两台机器上处理。
  • 一个作业i的处理时间是t,个时间单位。

假如每台机器在0时刻都是可用的,完成时间(finish time)或调度长度(length of a schedule)是指完成所有作业的时间。在一个非抢先调度中,一项作业i在一台机器上处理,从时刻 s i s_i si开始,到时刻 s i + t i s_i+t_i si+ti,结束。

我们的任务是写一个程序,实现在 m 台机器上执行 n 个作业的最小完成时间的调度。但是设计一个具有多项式时间复杂性的算法(即复杂度为 n k m l n^km^l nkml的算法,k和l是常数)来解决该问题非常难。调度问题是一个NP-复杂问题。

NP复杂问题和NP-完全问题

NP-复杂及NP-完全问题是指尚未找到具有多项式时间复杂性算法的问题。

NP-完全问题是一类判定问题,也就是说,对这类问题的每一个实例,答案为是或否。

NP-复杂问题可以是判定问题,也可以不是判定问题。

机器调度问题不是一个判定问题,因为对每一个问题实例,都是按照某种方案把作业分配给机器,以使完成时间最少。但是可以转换为判定问题。

对于机器调度问题,除了给定任务和机器外,还给定了时间TMin,要求确定是否存在一种调度,它的完成时间为 TMin 或更少。对于这类问题,答案为是或否。

NP-复杂问题的优化问题经常用**近似算法(approximation aigorithm)**解决,保证能找到近似最优解。

求解思路-最长处理时间(LPT)

在我们的调度问题中,采用了一个简单调度策略,称为最长处理时间(longest processing time,LPT),它的调度长度是最优调度长度的4/3-1/(3m)。在LPT算法中,作业按处理时间的递减顺序排列。当一个作业需要分配时,总是分配给最先变为空闲的机器。

**定理 12-2[Graham]*令 F(I)为在 m 台机器上执行作业集合 I 的最佳调度完成 时间,F(I)为采用 LPT 调度策略所得到的调度完成时间,则
F ( I ) F ∗ ( I ) ≤ 4 3 − 1 3 m \frac{F(I)}{F^*(I)}\leq\frac{4}{3}-\frac{1}{3m} F(I)F(I)343m1
可用堆来建立 LPT 调度方案,时间性能为 O(nlogn)。当n<m 时,只需要将作业 i 在0~t,时间内分配给机器i来处理。当 n>m 时,可以使用大根堆将作业按处理时间递增顺序排列。为了建立LPT调度方案,作业按相反次序进行分配。为了决定将一个作业分配给哪一台机器,必须知道哪台机器最先空闲。为此,维持一个m台机器的小根堆,元素类型为machineNode,它有数据成员avail(表示何时空闲)和id(机器编号)。machineNode类型实现()的重载。初始状态下所有machine的avail都为0。

用类jobNode表示作业,它有数据成员id(作业的唯一标识符)和time(作业需要的处理时间)。

举例

有3台机器,需要处理7个作业。7个作业的处理时间分别为(2,14,4,16,6,5,3)。3台机器的编号分别为M1、M2和M3。使用最长处理时间机器调度方法可以得到如下方案:

在这里插入图片描述

代码

main.cpp

#include <iostream>
#include <queue>
#include <vector>// 表示机器,id表示机器的id,avail表示机器什么时候有空
struct machineNode {int avail;int id;machineNode() {avail = 0;id = 0;}machineNode(int pid, int pavail) {avail = pavail;id = pid;}explicit operator int() const { return avail; }bool operator>(const machineNode &a) const { return avail > a.avail; }
};// 表示任务,id表示任务的id,time表示作业需要的处理时间
struct jobNode {int id;int time;jobNode() {id = 0;time = 0;}jobNode(int pid, int ptime) {id = pid;time = ptime;};explicit operator int() const { return time; }bool operator<(const jobNode &a) const { return time < a.time; }
};int main() {// 整个算法的时间复杂度为O(logn)// 初始化任务大根堆,初始化时间为O(taskVec.size()==n)const std::vector<jobNode> taskVec = {jobNode(1, 2), jobNode(2, 14), jobNode(3, 4), jobNode(4, 16), jobNode(5, 6),jobNode(6, 5), jobNode(7, 3)};std::priority_queue<jobNode, std::vector<jobNode>> tasks(taskVec.begin(), taskVec.end());// 初始化机器小根堆,初始化时间为O(machineVec.size()==m)const std::vector<machineNode> machineVec = {machineNode{1, 0}, machineNode{2, 0}, machineNode{3, 0}};std::priority_queue<machineNode, std::vector<machineNode>, std::greater<>> machines(machineVec.begin(),machineVec.end());// 执行了2n次top、2n次 pop和2n次 push操作,每次top的时间是0(1),machines的pop和push的时间是O(logm),tasks的pop和push的时间是O(logn)。// 因此此for循环的时间复杂度为O(nlogn)for (int i = 0; i < taskVec.size(); i++) {machineNode temp = machines.top();machines.pop();jobNode taskNode = tasks.top();tasks.pop();std::cout << "Schedule job " << taskNode.id << " on machine " << temp.id << " from " << temp.avail << " to "<< (temp.avail + taskNode.time) << std::endl;temp.avail += taskNode.time;machines.push(temp);}std::cout << std::endl;return 0;
}

运行结果

"C:\Users\15495\Documents\Jasmine\prj\_Algorithm\Data Structures, Algorithms and Applications in C++\_28LongestProcessingTime\cmake-build-debug\_28LongestProcessingTime.exe"
Schedule job 4 on machine 3 from 0 to 16
Schedule job 2 on machine 2 from 0 to 14
Schedule job 5 on machine 1 from 0 to 6
Schedule job 6 on machine 1 from 6 to 11
Schedule job 3 on machine 1 from 11 to 15
Schedule job 7 on machine 2 from 14 to 17
Schedule job 1 on machine 1 from 15 to 17Process finished with exit code 0

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Logback技术专题】「入门到精通系列教程」深入探索Logback日志框架的原理分析和开发实战技术指南(上篇)

深入探索Logback日志框架的原理分析和开发实战指南系列 Logback日志框架Logback基本模块logback-corelogback-classiclogback-accessLogback的核心类LoggerAppenderLayoutLayout和Appender filterlogback模块和核心所属关系 Logbackj日志级别日志输出级别日志级别介绍 Logback的…

【数据结构】树状数组总结

知识概览 树状数组有两个作用&#xff1a; 快速求前缀和 时间复杂度O(log(n))修改某一个数 时间复杂度O(log(n)) 例题展示 1. 单点修改&#xff0c;区间查询 题目链接 活动 - AcWing本活动组织刷《算法竞赛进阶指南》&#xff0c;系统学习各种编程算法。主要面向…

如何使用JavaScript 将数据网格绑定到 GraphQL 服务

前言 作为一名前端开发人员&#xff0c;GraphQL对于我们来说是令人难以置信的好用。它可以用来简化数据访问&#xff0c;这让我们的工作变得更加容易。 什么是 GraphQL&#xff1f;它是一个抽象层&#xff0c;位于任意数量的数据源之上&#xff0c;并为您提供一个简单的 API …

为什么选择计算机?大数据时代学习计算机的价值探讨

还记得当初自己为什么选择计算机? 计算机是在90年代兴起的专业,那时候的年轻人有驾照、懂外语、懂计算机是很时髦的事情! 当初你问我为什么选择计算机,我笑着回答:“因为我梦想成为神奇的码农!我想像编织魔法一样编写程序,创造出炫酷的虚拟世界!”谁知道,我刚入门的…

UE5 第三人称游戏模板白屏问题

文章目录 问题背景问题解决解决方法一解决方法二解决方法三解决方法四 问题背景 在虚幻引擎5创建第三人称游戏模板时&#xff0c;打开场景显示白屏&#xff0c;物体可以点击选中&#xff0c;出现类似这种问题&#xff0c;考虑是曝光的原因&#xff0c;在确定引擎没有问题的情况…

C语言—小小圣诞树

这个代码会询问用户输入圣诞树的高度&#xff0c;然后根据输入的高度在控制台上显示相应高度的圣诞树。 #include <stdio.h>int main() {int height, spaces, stars;printf("请输入圣诞树的高度: ");scanf("%d", &height);spaces height - 1;st…

D3132|贪心算法

435.无重叠区间 初始思路&#xff1a; 我的思路就是如果有两个区间重叠&#xff0c;保留end比较小的那个区间&#xff0c;删除end比较大的区间。 class Solution {public int eraseOverlapIntervals(int[][] intervals) {Arrays.sort(intervals, new Comparator<int[]>…

CentOS7安装Docker及添加阿里云镜像加速详细教程

Docker官方安装教程网站&#xff1a;Install Docker Engine on CentOS | Docker Docs 具体流程如下&#xff1a; 1.确定你是CentOS7及以上版本 cat /etc/redhat-release 2.yum安装gcc相关 yum -y install gcc yum -y install gcc-c 3.安装需要的软件包 3.1安装docker引擎…

力扣刷题-二叉树-找树左下角的值

513 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1&#xff1a; 示例 2&#xff1a; 思路 层序遍历 直接层序遍历&#xff0c;因为题目说了是最底层&#xff0c;最左边的值&a…

配置策略路由(基于IP地址)示例

策略路由简介 定义 策略路由PBR&#xff08;Policy-Based Routing&#xff09;是一种依据用户制定的策略进行路由选择的机制&#xff0c;其优先级高于直连路由、静态路由和通过动态路由协议生成的路由。设备配置策略路由后&#xff0c;若接收的报文&#xff08;包括二层报文&…

LCR 146. 螺旋遍历二维数组

解题思路&#xff1a; class Solution {public int[] spiralArray(int[][] array) {if(array.length 0) return new int[0];int l 0, r array[0].length - 1;int t 0, b array.length - 1;int x 0;int[] res new int[(r 1) * (b 1)];while(true) {for(int i l; i <…

geemap学习笔记028:Landsat8计算时间序列NDVI并导出

前言 本节则是以Landsat8影像数据为例&#xff0c;进行NDVI时间序列计算&#xff0c;并将得到的时间序列NDVI进行展示并导出。 1 导入库并显示地图 import ee import geemap import datetime import pandas as pd import os ee.Initialize()2 定义时间范围 # 定义日期范围 …