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

2024-01-26 04:12

本文主要是介绍P1065 [NOIP2006 提高组] 作业调度方案题目,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

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

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

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

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

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

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

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

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

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

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

工件号工序 1工序 2
11/32/2
21/22/5
32/21/4

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

方案1,用时10:

时间12345678910
机器1执行工序1-11-11-12-12-13-23-23-23-2
机器2执行工序3-13-11-21-22-22-22-22-22-2

方案2,用时12:

时间123456789101112
机器1执行工序1-11-11-12-12-13-23-23-23-2
机器2执行工序1-21-23-13-12-22-22-22-22-2

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

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

输入输出格式

输入格式

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

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

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

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

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

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

输出格式

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

输入输出样例

输入样例

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

输出样例

10

解析

题目已经给出了安排好的工序,而每个工序需要在几号机上完成以及每个工序的时间也给了出来,我们要做的就是合理安排机器的工作,让总的加工时间最短。

按照题意的约定,最短方案有且只有一种,而且不必判断输入的合法性。

我们可以把机器想成若干个「时间线」,在这条时间线上去安排工作。

那么明显的,每个时间段对应的机器就只有俩状态:1.我在干活     2.我闲着呢

而每一个工件也有自己的加工要求,对于每个工件的工序,总应该先完成小号工序再完成大号工序,也就是必须顺着编号来。

每台机器只能在某时刻进行一种工作,并且后面的安排不能把前面的安排改动掉。

模拟的思想便是从左到右无限扫描整个时间线,然后去尝试插空。

有三个辅助数组,第一个是cnt_now_work_step,它表示当前取到工件的工序数。根据之前输入的workline,每个数都代表一个安排的工序,这个数组就是用来方便后面处理工序的。第二个是lasttime,它代表某个工件出现的最晚的时间(点),它可以用来方便我们扫描时间线,因为每一个工件必须要完全完成上一道工序后才能接着继续下一道工序。第三个是二维bool数组timeline,它代表某一台机器在某一个时间(点)上是不是正在干活。

有了这三个辅助数组,我们就可以开始按照模拟的思路写代码了。

我们取当前工件nowitem[i],让cnt_now_work_step[nowitem]++,即代表这个工件的工序+1,用nownumber记录当前工件在当前工序时位于哪一台机器,costtime表示做完这道工序应该花费的时间,lasttime[nowitem]+1便是我们扫描时间线的开端,注意lasttime记录的是时间点。这个for没有终止条件,因为时间轴可能会无穷远。

接下来是关键,判断从这个时间点到干完这道工序,机器有没有空,如果机器表示“我闲着呢”,那么就把这道工序安排给机器的这个时间段,更新timeline和lasttime(lasttime[nowitem] = time + costtime - 1,干完活之后这个工件出现的最晚的时间点应该是这道新工序做完的那一刻),然后更新操作立即break掉,继续扫描时间线。如果机器表示“这个时间段我在干其他活”,那这个任务就不能放在这一段,时间线继续扫描。

这个判断这里用一个函数来实现,它传入起始时间点和终止时间点和工件编号,然后去判断它的timeline。循环完所有的工件,整个的时间轴也就确定了。最后去寻找ans,ans应该等于值最大的那个lasttime(即这个工件最后才做完)。输出ans即可。

代码

#include<iostream>
#define maxn 100
using namespace std;
int n,m;//定义工件数和机器数 
int ans = 0;//最后输出的结果 
int worklist[maxn * maxn];
int worknumber[maxn][maxn];
int worktime[maxn][maxn];
int cnt_now_work_step[maxn];
int lasttime[maxn];
bool timeline[maxn * maxn][maxn * maxn];//某一台机器在某一个时间(点)上是不是正在干活bool check_in_line(int begin_time_point,int end_time_length,int workid){for (int time = begin_time_point; time <= end_time_length;time++)if (timeline[workid][time])return false;return true;    
}//判断机器是不是空闲 int main(){cin >> m >> n;//输入机器数和工件数 for (int i=1;i<=n*m;i++){ cin >> worklist[i];//输入给定的安排顺序 } for (int i=1;i<=n;i++){ for (int j=1;j<=m;j++){ cin >> worknumber[i][j];//每一工件每个工序的机器号 }} for (int i=1;i<=n;i++){ for (int j=1;j<=m;j++){ cin >> worktime[i][j];//每个工件每个工序的加工时间 }} for (int i=1;i<=n*m;i++){int nowitem = worklist[i];//工件的安排顺序 cnt_now_work_step[nowitem]++;//当前取到工件的工序数int nownumber = worknumber[nowitem][cnt_now_work_step[nowitem]];//当前工件在当前工序时位于哪一台机器 int costtime = worktime[nowitem][cnt_now_work_step[nowitem]];//当前工件做完当前工序的加工时间 for (int time = lasttime[nowitem]+1;;time++)//扫描时间轴if (check_in_line(time,time+costtime-1,nownumber)){for (int marktime = time;marktime <= time+costtime-1;marktime++)timeline[nownumber][marktime] = true;lasttime[nowitem] = time + costtime - 1;break;}}for (int i=1;i<=n;i++)ans = max(ans,lasttime[i]);cout << ans << endl;return 0;
}

这篇关于P1065 [NOIP2006 提高组] 作业调度方案题目的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/645607

相关文章

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

Java进行文件格式校验的方案详解

《Java进行文件格式校验的方案详解》这篇文章主要为大家详细介绍了Java中进行文件格式校验的相关方案,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、背景异常现象原因排查用户的无心之过二、解决方案Magandroidic Number判断主流检测库对比Tika的使用区分zip

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

IDEA中Git版本回退的两种实现方案

《IDEA中Git版本回退的两种实现方案》作为开发者,代码版本回退是日常高频操作,IntelliJIDEA集成了强大的Git工具链,但面对reset和revert两种核心回退方案,许多开发者仍存在选择... 目录一、版本回退前置知识二、Reset方案:整体改写历史1、IDEA图形化操作(推荐)1.1、查看提

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

MySQL中闪回功能的方案讨论及实现

《MySQL中闪回功能的方案讨论及实现》Oracle有一个闪回(flashback)功能,能够用户恢复误操作的数据,这篇文章主要来和大家讨论一下MySQL中支持闪回功能的方案,有需要的可以了解下... 目录1、 闪回的目标2、 无米无炊一3、 无米无炊二4、 演示5、小结oracle有一个闪回(flashb

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

Java嵌套for循环优化方案分享

《Java嵌套for循环优化方案分享》介绍了Java中嵌套for循环的优化方法,包括减少循环次数、合并循环、使用更高效的数据结构、并行处理、预处理和缓存、算法优化、尽量减少对象创建以及本地变量优化,通... 目录Java 嵌套 for 循环优化方案1. 减少循环次数2. 合并循环3. 使用更高效的数据结构4