洛谷P1248 加工生产调度

流水作业调度问题

N个作业要在两台机器M1M2组成的流水线上完成加工。每个作业i都必须先花时间aiM1上加工,然后花时间biM2上加工。
确定N个作业的加工顺序,使得从作业1在机器M1上加工开始到作业N在机器M2上加工完为止所用的总时间最短。

【算法】

直观上,最优调度一定让M1没有空闲,M2的空闲时间尽量短。

Johnson算法:N1a<b的作业集合,N2b的作业集合,将N的作业按a非减序排序,N2中的作业按照b非增序排序,则N1作业接N2作业构成最优顺序。

算法的程序易于实现,时间复杂度为O(nlogn),正确性需要证明。


P1248 加工生产调度

【问题描述】

某工厂收到了N个产品的订单,这N个产品分别在ab两个车间加工,并且必须先在a加工后才可以送到b车间加工。
某个产品iab两车间加工的时间分别为aibi。怎样安排这N个产品的加工顺序,才能总的加工时间最短?
这里所说的加工时间是指:从开始加工第一个产品到所有的产品都已在两车间加工完毕的时间。

【输入格式】

第一行仅一个数据N(0<N<1000),表示产品的数量。
接下来N个数据是表示这N个产品在a车间加工,各自所要的时间(都是整数)。最后的N个数据是表示这N个产品在b车间加工,各自所要的时间(都是整数)

【输出格式】

第一行一个数据,表示最短的加工时间。
第二行是一种用时最短的产品加工顺序。

【样例输入】

5
3 5 8 7 10
6 2 1 4 9

【样例输出】

34
1 5 4 2 3


【思路】

求一个加工顺序使得加工总用时最短,就是让机器的空闲时间最短。一旦a机器开始加工,则a机器将会不停地进行作业,关键是b机器在加工过程中有可能要等待a机器。很明显第一个部件在a机器上加工时,b机器必须等待,最后一个部件在b机器上加工时,a机器也在等待b机器的完工。
可以大胆猜想,要使机器总的空闲时间最短就要把在a机器上加工时间最短的部件最先加工,这样使得b机器能在最短的空闲时间内开始加工;把在b机器上加工时间最短的部件放在最后加工,这样使得a机器用最短时间等待b机器完工。

于是我们可以设计出这样的贪心策略:设MiminaibiM按照从小到大的顺序排序,然后从第1个开始处理,若Miai,则将它排在从头开始的作业后面,若Mibi,则将它排在从尾开始的作业前面。
例如:
N=5,
a1a2a3a4a5358710
b1b2b3b4b562149
M1M2M3M4M532149
排序之后为M3M2M1M4M5
处理M3: ∵ M3b3,∴M3排在后面;加入M3之后的加工顺序为3
处理M2: ∵ M2b2,∴M2排在后面;加入M2之后的加工顺序为23
处理M1: ∵ M1a1,∴M1排在前面;加入M1之后的加工顺序为123
处理M4: ∵ M4b4,∴M4排在后面;加入M4之后的加工顺序为1423
处理M5: ∵ M5b5,∴M5排在后面;加入M5之后的加工顺序为15423
则最优加工顺序就是15423,最短时间为34。
显然这个结果是最优解。
问题是这种贪心策略是否正确呢?还需证明。

【证明】

去年刚学OI时写的(萌新刚学OI),字写得渣。




Code

#include<bits/stdc++.h>
using namespace std;
const int N = 2005;
struct data {
	int id,a,b;
} J[N], ans[N];
int n;
inline bool cmp(const data &A, const data &B) {//Jhonson不等式排序 
	return min(A.a, A.b) < min(B.a, B.b);
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		scanf("%d", &J[i].a);
		J[i].id = i;//原数组下标 
	}
	for(int i = 1; i <= n; ++i) scanf("%d", &J[i].b);
	sort(J + 1, J + 1 + n, cmp);
	for(int i = 1, p = 1, q = n; i <= n; ++i) {//p--队头 q--队尾 
		if(J[i].a <= J[i].b) ans[p++] = J[i];
		else ans[q--] = J[i];
	}
	int time1 = 0, time2 = 0;//time1--A机器上加工用时 time2--B机器上加工用时 
	for(int i = 1; i <= n; ++i) {
		time1 += ans[i].a;//第i件产品在A机器上所用时间 
		time2 = max(time1, time2);//在A机器上加工完才能到B机器 未加工完需要等待 
		time2 += ans[i].b;//第i件产品在B机器上所用时间 
	}
	printf("%d\n", time2);//最后一件在B机器加工完的时刻为结束时刻 
	for(int i = 1; i <= n; ++i) printf("%d ", ans[i].id);//输出方案 
	return 0;
}
posted @   宇興  阅读(592)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示