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 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;}}
}
- 我们通过循环来模拟处理每个任务步骤。currentJob 是当前任务步骤对应的任务编号。
- 我们递增jobStep[currentJob],表示当前任务已完成的步骤数。然后,我们获取当前步骤需要在哪台机器上执行,以及需要多少时间。
- 我们使用 s来记录在机器上找到的可用时间段的长度。我们从上次这个任务完成的时间(lastJobTime[currentJob])的下一个时间点开始查找。
- 我们检查 machineTimeline[currentMachineId][j],如果等于 0,表示这个时间点机器是空闲的,我们递增 s;否则,表示机器正在被占用,我们将 s 重置为 0。
- 当 s 的值达到当前步骤所需的时间时,说明我们找到了一个满足条件的时间段。我们将从 j - currentTimeCost + 1 到j 的时间段标记为机器被占用。
- 如果当前时间点 j 大于记录的 answer,我们更新 answer,以便在之后输出。
- 最后,我们更新 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 个工件,每个工件都有 m m m 道工序,每道工序都在不同的指定的机器上完成。每个工件的每道工序都有指定的加工时间。 每个工件的每个工序称为一个操作,…...

设计模式三原则
1.1单一职责原则 C 面向对象三大特性之一的封装指的就是将单一事物抽象出来组合成一个类,所以我们在设计类的时候每个类中处理的是单一事物而不是某些事物的集合。 设计模式中所谓的单一职责原则,就是对一个类而言,应该仅有一个引起它变化的原…...
dll载入时发生的事情
dll是什么 DLL 是一个包含可由多个程序同时使用的代码和数据的库。 对于 Windows 操作系统,操作系统的大部分功能都由 DLL 提供。 另外,当您在这些 Windows 操作系统之一上运行某一程序时,该程序的很多功能可能是由 DLL 提供的。 例如&…...

k8s-ingress-context deadline exceeded
报错: 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盒模型
盒模型的组成: content,padding,border,margin 盒模型的分类: 内容盒模型(标准盒模型) — 盒子的宽widthpaddingborder 边框盒模型 — 盒子的宽width 参考 盒模型【CSS面试题】_哔哩哔哩_bilibili...
cuda11.1和cuDNN v8.8.1的安装目录问题
cuda的不同版本文件路径是不一致的,在cuda10.1中,配置cudnn的文件路径是: 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中,文件路径…...
微信小程序scroll-view的触发机制
一、scroll-view 可滚动视图区域。使用竖向滚动时,需要给scroll-view一个固定高度,通过 WXSS 设置 height。组件属性的长度单位默认为px,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定位还是很复杂的,感觉有必要详细了解一下 RectTransform 继承自Transform。他的local position由其他几个变量控制。建议不要直接设置position 目的是为了实现UI自动布局。这套方法将绝对定位,相对定位&a…...
《存储IO路径》专题:DDIO对系统性能的影响
DDIO对系统性的影响 想象一下,有一天,你在网上冲浪,突然,一个巨大的数据包从天而降,直接砸在了你的电脑上。你一看,哇,是全新的《英雄联盟》版本!你迫不及待地打开了游戏,发现加载速度简直快如闪电。 那么,这个神奇的事情是怎么发生的呢? 其实,这都要归功于DDIO技…...

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

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

Linux 终端命令之文件目录操作,对比Dos相关命令
目录 前言 基础命令(文件目录相关的) cd命令 【英文帮助】 【对应Dos命令】 pwd命令 【英文帮助】 【对应Dos命令】 ls命令 【英文帮助】 【对应Dos命令】 tree命令 【英文帮助】 【对应Dos命令】 mkdir命令 【英文帮助】 【对应Dos命令…...
C++学习第十八天----switch语句
1. ?:运算符 条件运算符,又叫三元运算符; 该运算符的通用格式为: expression1?expression2 :expression3; 意义是假如1为true,则整个条件表达式的值为2的值,否则为3的值&…...
基于poi生成excel模板并生成下拉选择框
直接上代码(有注释) public void downloadImportTemplate(HttpServletResponse response) {try {ServletOutputStream outputStream response.getOutputStream();//创建工作表XSSFWorkbook workbook new XSSFWorkbook();//标题行的标题List<String…...

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

通过IP地址如何防范钓鱼网站诈骗?
随着互联网的普及和发展,钓鱼网站诈骗的风险日益增加。钓鱼网站通过伪装成合法网站,诱导用户输入个人敏感信息进而进行非法活动。IP地址作为网络通信的基本单位,可以在一定程度上帮助我们防范钓鱼网站诈骗。本文将探讨IP地址防范钓鱼网站诈骗…...
useEffect使用详解
useEffect是React中的一个钩子函数,用于处理副作用操作。副作用是指在组件渲染过程中,可能会对外部环境产生影响的操作,比如数据获取、订阅事件、操作DOM等。 useEffect接受两个参数:一个是副作用函数,另一个是依赖数…...

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

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

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...