当前位置: 首页 > news >正文

P1065 [NOIP2006 提高组] 作业调度方案

[NOIP2006 提高组] 作业调度方案

题目描述

我们现在要利用 m m m 台机器加工 n n n 个工件,每个工件都有 m m m 道工序,每道工序都在不同的指定的机器上完成。每个工件的每道工序都有指定的加工时间。

每个工件的每个工序称为一个操作,我们用记号 j-k 表示一个操作,其中 j j j 1 1 1 n n n 中的某个数字,为工件号; k k k 1 1 1 m m m 中的某个数字,为工序号,例如 2-4 表示第 2 2 2 个工件第 4 4 4 道工序的这个操作。在本题中,我们还给定对于各操作的一个安排顺序。

例如,当 n = 3 , m = 2 n=3,m=2 n=3,m=2 时,1-1,1-2,2-1,3-1,3-2,2-2 就是一个给定的安排顺序,即先安排第 1 1 1 个工件的第 1 1 1 个工序,再安排第 1 1 1 个工件的第 2 2 2 个工序,然后再安排第 2 2 2 个工件的第 1 1 1 个工序,等等。

一方面,每个操作的安排都要满足以下的两个约束条件。

  1. 对同一个工件,每道工序必须在它前面的工序完成后才能开始;

  2. 同一时刻每一台机器至多只能加工一个工件。

另一方面,在安排后面的操作时,不能改动前面已安排的操作的工作状态。

由于同一工件都是按工序的顺序安排的,因此,只按原顺序给出工件号,仍可得到同样的安排顺序,于是,在输入数据中,我们将这个安排顺序简写为 1 1 2 3 3 2

还要注意,“安排顺序”只要求按照给定的顺序安排每个操作。不一定是各机器上的实际操作顺序。在具体实施时,有可能排在后面的某个操作比前面的某个操作先完成。

例如,取 n = 3 , m = 2 n=3,m=2 n=3,m=2,已知数据如下(机器号/加工时间):

工件号工序 1 1 1工序 2 2 2
1 1 1 1 / 3 1/3 1/3 2 / 2 2/2 2/2
2 2 2 1 / 2 1/2 1/2 2 / 5 2/5 2/5
3 3 3 2 / 2 2/2 2/2 1 / 4 1/4 1/4

则对于安排顺序 1 1 2 3 3 2,下图中的两个实施方案都是正确的。但所需要的总时间分别是 10 10 10 12 12 12

当一个操作插入到某台机器的某个空档时(机器上最后的尚未安排操作的部分也可以看作一个空档),可以靠前插入,也可以靠后或居中插入。为了使问题简单一些,我们约定:在保证约束条件( 1 1 1)( 2 2 2)的条件下,尽量靠前插入。并且,我们还约定,如果有多个空档可以插入,就在保证约束条件( 1 1 1)( 2 2 2)的条件下,插入到最前面的一个空档。于是,在这些约定下,上例中的方案一是正确的,而方案二是不正确的。

显然,在这些约定下,对于给定的安排顺序,符合该安排顺序的实施方案是唯一的,请你计算出该方案完成全部任务所需的总时间。

输入格式

1 1 1 行为两个正整数 m m m, n n n,用一个空格隔开,
(其中 m ( < 20 ) m(<20) m(<20) 表示机器数, n ( < 20 ) n(<20) n(<20) 表示工件数)

2 2 2 行: m × n m \times n m×n 个用空格隔开的数,为给定的安排顺序。

接下来的 2 n 2n 2n 行,每行都是用空格隔开的 m m m 个正整数,每个数不超过 20 20 20

其中前 n n n 行依次表示每个工件的每个工序所使用的机器号,第 1 1 1 个数为第 1 1 1 个工序的机器号,第 2 2 2 个数为第 2 2 2 个工序机器号,等等。

n n n 行依次表示每个工件的每个工序的加工时间。

可以保证,以上各数据都是正确的,不必检验。

输出格式

1 1 1 个正整数,为最少的加工时间。

样例 #1

样例输入 #1

2 3
1 1 2 3 3 2
1 2 
1 2 
2 1
3 2 
2 5 
2 4

样例输出 #1

10

提示

NOIP 2006 提高组 第三题

解题思路:

当处理这个问题时,我们可以将其类比成一个工厂里的任务分配问题。下面是一个小学生都能理解的解题思路,附带一些简单的代码解释。

1.明确问题: 我们有很多台机器和很多个任务,每个任务都有几个步骤,每个步骤都需要在某个机器上完成,并且需要花一些时间。

2.获取机器和任务数量: 首先,从输入中读取机器和任务的数量。

int numMachines, numJobs;
cin >> numMachines >> numJobs;

3.记录每个任务的信息: 对于每个任务,我们需要知道每个步骤应该在哪台机器上完成,以及需要花多少时间。

struct JobStep {int machineId;int timeCost;
};JobStep jobs[21][21];  // 假设最多有 20 个任务,每个任务最多 20 个步骤

4.获取任务步骤的信息: 针对每个任务和每个步骤,读取它应该在哪台机器上完成以及需要花多少时间。

for (int i = 1; i <= numJobs; i++) {for (int j = 1; j <= numMachines; j++) {cin >> jobs[i][j].machineId;}
}for (int i = 1; i <= numJobs; i++) {for (int j = 1; j <= numMachines; j++) {cin >> jobs[i][j].timeCost;}
}

5.任务列表: 我们会获取一个任务列表,告诉我们任务的执行顺序。

int jobList[501];  // 假设最多有 500 个任务步骤for (int i = 1; i <= numMachines * numJobs; i++) {cin >> jobList[i];
}

6.模拟执行: 对于每个任务步骤,我们会找到合适的时间段,然后更新机器的时间线,并记录任务的完成时间。这段代码比较难以理解所以我把他再次分为几点:

int machineTimeline[21][100001] = {0};  // 机器时间线,用 0 表示空闲,1 表示占用
int jobStep[21] = {0};  // 每个任务完成的步骤
int lastJobTime[21] = {0};  // 每个任务的上次完成时间
int answer = 0;  // 最终答案,所有任务都完成的时间点

6.1:这些数组用于存储我们模拟中需要的信息。machineTimeline 记录每台机器的时间线,jobStep 记录每个任务已经完成的步骤数,lastJobTime 记录每个任务上一次完成的时间,answer 存储最终的答案,即所有任务都完成的时间点。

for (int i = 1; i <= numMachines * numJobs; i++) {int currentJob = jobList[i];jobStep[currentJob]++;int currentMachineId = jobs[currentJob][jobStep[currentJob]].machineId;int currentTimeCost = jobs[currentJob][jobStep[currentJob]].timeCost;int s = 0;for (int j = lastJobTime[currentJob] + 1; ; j++) {if (machineTimeline[currentMachineId][j] == 0) {s++;} else {s = 0;}if (s == currentTimeCost) {for (int k = j - currentTimeCost + 1; k <= j; k++) {machineTimeline[currentMachineId][k] = 1;}if (j > answer) answer = j;lastJobTime[currentJob] = j;break;}}
}
  1. 我们通过循环来模拟处理每个任务步骤。currentJob 是当前任务步骤对应的任务编号。
  2. 我们递增jobStep[currentJob],表示当前任务已完成的步骤数。然后,我们获取当前步骤需要在哪台机器上执行,以及需要多少时间。
  3. 我们使用 s来记录在机器上找到的可用时间段的长度。我们从上次这个任务完成的时间(lastJobTime[currentJob])的下一个时间点开始查找。
  4. 我们检查 machineTimeline[currentMachineId][j],如果等于 0,表示这个时间点机器是空闲的,我们递增 s;否则,表示机器正在被占用,我们将 s 重置为 0。
  5. 当 s 的值达到当前步骤所需的时间时,说明我们找到了一个满足条件的时间段。我们将从 j - currentTimeCost + 1 到j 的时间段标记为机器被占用。
  6. 如果当前时间点 j 大于记录的 answer,我们更新 answer,以便在之后输出。
  7. 最后,我们更新 lastJobTime[currentJob],表示当前任务上一次完成的时间。

注意:s的解释
在这段代码中,s 是用来计算连续空闲时间段的计数器。当我们需要找到一个连续时间段,足够容纳当前步骤所需的时间时,我们使用 s 来记录连续空闲时间段的长度。

在循环中,我们逐步递增 j,检查机器时间线上的每个时间点。如machineTimeline[currentMachineId][j] 表示机器上的这个时间点空闲(值为 0),那么我们递增 s。如果不是空闲的,我们将 s 重置为 0,因为我们需要找到连续的空闲时间段。

当 s 的值等于当前步骤所需的时间时(s == currentTimeCost),说明我们找到了一个足够长的连续空闲时间段,可以在机器上执行当前任务步骤。然后我们会将这个时间段标记为机器被占用,并更新相应的时间和计数器。

所以,s 在这里充当了一个计数器,帮助我们在机器时间线上找到足够长的连续空闲时间段,以满足当前任务步骤的时间要求。

最后:附上完整代码

#include <iostream>using namespace std;int numMachines, numJobs;
int jobList[501];
struct JobInfo {int machineId;int timeCost;
} jobs[21][21];
int machineTimeline[21][100001] = {0};
int jobStep[21] = {0};
int lastJobTime[21] = {0};
int answer = 0;int main() {// 读取机器和任务数量cin >> numMachines >> numJobs;// 读取任务列表for (int i = 1; i <= numMachines * numJobs; i++) {cin >> jobList[i];}// 读取每个任务步骤的机器编号for (int i = 1; i <= numJobs; i++) {for (int j = 1; j <= numMachines; j++) {cin >> jobs[i][j].machineId;}}// 读取每个任务步骤的时间花费for (int i = 1; i <= numJobs; i++) {for (int j = 1; j <= numMachines; j++) {cin >> jobs[i][j].timeCost;}}// 处理每个任务for (int i = 1; i <= numMachines * numJobs; i++) {int currentJob = jobList[i];jobStep[currentJob]++;int currentMachineId = jobs[currentJob][jobStep[currentJob]].machineId;int currentTimeCost = jobs[currentJob][jobStep[currentJob]].timeCost;int s = 0;// 查找机器上的下一个可用时间段for (int j = lastJobTime[currentJob] + 1; ; j++) {if (machineTimeline[currentMachineId][j] == 0) {s++;} else {s = 0;}if (s == currentTimeCost) {// 更新机器时间线以表示当前任务for (int k = j - currentTimeCost + 1; k <= j; k++) {machineTimeline[currentMachineId][k] = 1;}// 使用最新的完成时间更新答案if (j > answer) answer = j;// 更新当前任务的上次完成时间lastJobTime[currentJob] = j;break;}}}// 输出最终答案cout << answer;return 0;
}

相关文章:

P1065 [NOIP2006 提高组] 作业调度方案

[NOIP2006 提高组] 作业调度方案 题目描述 我们现在要利用 m m m 台机器加工 n n n 个工件&#xff0c;每个工件都有 m m m 道工序&#xff0c;每道工序都在不同的指定的机器上完成。每个工件的每道工序都有指定的加工时间。 每个工件的每个工序称为一个操作&#xff0c;…...

设计模式三原则

1.1单一职责原则 C 面向对象三大特性之一的封装指的就是将单一事物抽象出来组合成一个类&#xff0c;所以我们在设计类的时候每个类中处理的是单一事物而不是某些事物的集合。 设计模式中所谓的单一职责原则&#xff0c;就是对一个类而言&#xff0c;应该仅有一个引起它变化的原…...

dll载入时发生的事情

dll是什么 DLL 是一个包含可由多个程序同时使用的代码和数据的库。 对于 Windows 操作系统&#xff0c;操作系统的大部分功能都由 DLL 提供。 另外&#xff0c;当您在这些 Windows 操作系统之一上运行某一程序时&#xff0c;该程序的很多功能可能是由 DLL 提供的。 例如&…...

k8s-ingress-context deadline exceeded

报错&#xff1a; rancher-rke-01:~/rke # helm install rancher rancher-latest/rancher --namespace cattle-system --set hostnamewww.rancher.local Error: INSTALLATION FAILED: Internal error occurred: failed calling webhook "validate.nginx.ingress.kube…...

css盒模型

盒模型的组成&#xff1a; content&#xff0c;padding&#xff0c;border&#xff0c;margin 盒模型的分类&#xff1a; 内容盒模型(标准盒模型) — 盒子的宽widthpaddingborder 边框盒模型 — 盒子的宽width 参考 盒模型【CSS面试题】_哔哩哔哩_bilibili...

cuda11.1和cuDNN v8.8.1的安装目录问题

cuda的不同版本文件路径是不一致的&#xff0c;在cuda10.1中&#xff0c;配置cudnn的文件路径是&#xff1a; sudo cp cuda/include/cudnn.h /usr/local/cuda-10.1/include/ sudo cp -P cuda/lib64/libcudnn* /usr/local/cuda-10.1/lib64/但是在cuda11.1中&#xff0c;文件路径…...

微信小程序scroll-view的触发机制

一、scroll-view 可滚动视图区域。使用竖向滚动时&#xff0c;需要给scroll-view一个固定高度&#xff0c;通过 WXSS 设置 height。组件属性的长度单位默认为px&#xff0c;2.4.0起支持传入单位(rpx/px)。 两个属性是作为上拉加载下拉刷新触发事件 scroll-view属性bindrefresh…...

为本地文件创建URL

1.搭建Nginx流媒体服务器 2.nginx.conf中添加 server {#listen 80 default_server;#listen [::]:80 default_server;location /var/www/html/Dir {autoindex on;}root /var/www/html; # 设置默认网页的根目录index index.html; # 设置默认网页的文件名}在/var/www/html中加…...

UI位置与布局

UI位置与布局 引言 发现UGUI的RectTransform定位还是很复杂的&#xff0c;感觉有必要详细了解一下 RectTransform 继承自Transform。他的local position由其他几个变量控制。建议不要直接设置position 目的是为了实现UI自动布局。这套方法将绝对定位&#xff0c;相对定位&a…...

《存储IO路径》专题:DDIO对系统性能的影响

DDIO对系统性的影响 想象一下,有一天,你在网上冲浪,突然,一个巨大的数据包从天而降,直接砸在了你的电脑上。你一看,哇,是全新的《英雄联盟》版本!你迫不及待地打开了游戏,发现加载速度简直快如闪电。 那么,这个神奇的事情是怎么发生的呢? 其实,这都要归功于DDIO技…...

ModaHub魔搭社区:WinPlan经营大脑数据采集

目录 WinPlan经营大脑数据采集介绍 WinPlan经营大脑数据采集模版 WinPlan经营大脑数据采集介绍 基于指标、维度来创建业务表单,通过业务表单的形式来采集实际数据,最终生成企业统一的经营数据库。由于需要客户创建数据采集模版(业务流程),然后可以基于各个业务模版作为…...

缓存最佳实践

目录 前言 一、Cache Aside&#xff08;旁路缓存&#xff09;策略 二、不一致解决场景及解决方案 一、数据库主从不一致 二、缓存与数据库不一致 三、问题分析 三、缓存误用 一、多服务共用缓存实例 二、调用方缓存数据 三、缓存作为服务与服务之间传递数据的媒介 四…...

Linux 终端命令之文件目录操作,对比Dos相关命令

目录 前言 基础命令&#xff08;文件目录相关的&#xff09; cd命令 【英文帮助】 【对应Dos命令】 pwd命令 【英文帮助】 【对应Dos命令】 ls命令 【英文帮助】 【对应Dos命令】 tree命令 【英文帮助】 【对应Dos命令】 mkdir命令 【英文帮助】 【对应Dos命令…...

C++学习第十八天----switch语句

1. &#xff1f;:运算符 条件运算符&#xff0c;又叫三元运算符&#xff1b; 该运算符的通用格式为&#xff1a; expression1&#xff1f;expression2 &#xff1a;expression3&#xff1b; 意义是假如1为true&#xff0c;则整个条件表达式的值为2的值&#xff0c;否则为3的值&…...

基于poi生成excel模板并生成下拉选择框

直接上代码&#xff08;有注释&#xff09; public void downloadImportTemplate(HttpServletResponse response) {try {ServletOutputStream outputStream response.getOutputStream();//创建工作表XSSFWorkbook workbook new XSSFWorkbook();//标题行的标题List<String…...

Redis五种类型

Redis 基础类型 String 应用场景 缓存功能&#xff1a;string 最常用的就是缓存功能&#xff0c;会将一些更新不频繁但是查询频繁的数据缓存起来&#xff0c;以此来减轻 DB 的压力。 底层实现 如果字符串对象保存的是一个字符串值&#xff0c; 并且这个字符串值的长度大于…...

通过IP地址如何防范钓鱼网站诈骗?

随着互联网的普及和发展&#xff0c;钓鱼网站诈骗的风险日益增加。钓鱼网站通过伪装成合法网站&#xff0c;诱导用户输入个人敏感信息进而进行非法活动。IP地址作为网络通信的基本单位&#xff0c;可以在一定程度上帮助我们防范钓鱼网站诈骗。本文将探讨IP地址防范钓鱼网站诈骗…...

useEffect使用详解

useEffect是React中的一个钩子函数&#xff0c;用于处理副作用操作。副作用是指在组件渲染过程中&#xff0c;可能会对外部环境产生影响的操作&#xff0c;比如数据获取、订阅事件、操作DOM等。 useEffect接受两个参数&#xff1a;一个是副作用函数&#xff0c;另一个是依赖数…...

element-table的动态操作,自动以表格,动态新增行、列,删除行列

灵活的自定义表格行列以及增删改查的操作,右键选中列则是列的删除&#xff0c;效果如下 <template><div class"st-table"><div style"width: 100%"><el-button click"addRow()" type"primary" icon"CircleP…...

python--文件管理系统

文件系统管理项目说明文档 项目说明 基本任务 在内存中开辟一个空间作为文件存储器&#xff0c;在其上实现一个简单的文件系统退出这个文件系统时&#xff0c;需要该文件系统的内容保存到磁盘上&#xff0c;以便下次可以将其回复到内存中来 具体要求 文件存储空间管理可采取链…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...