原题链接:
https://www.luogu.com.cn/problem/P1248
升级版贪心类型的模板题之一,也就是Johnson算法的模板。
题目解析:
本题是要求一个加工顺序使得总的加工时间最少,而要使加工时间最少,就是让各车间的空闲时间最少。
此题要求必须先送到A再送到B,所以要使A和B两车间的空闲时间最少:
(1)就要把在A车间加工时间最短的部件最先加工,这样使得B车间能更快开始加工。
(2)就要把在B车间加工时间最短的部件最后加工,这样使得A车间的空闲时间最短。
流水作业调度问题的Johnson算法如下:
1. 令$ N_1 = \{ i | a_i < b_i \} $ , $ N_2= \{ i|a_i>=b_i \} $
2. 将$N_1$中的作业按$a_i$升序排序;将$N_2$中的作业按$b_i$降序排序
3. $N_1$中的作业接$N_2$中的作业构成Johnson法则的最优调度。
Johnson算法证明:
https://www.luogu.com.cn/blog/79017/solution-p1248
下面是Johnson算法的实现
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e4 + 10;
struct Node{
int time, index;//工件i在A,B上最短加工时间和序号i
}job[maxn];
bool cmp(Node &a, Node &b){
return a.time < b.time;//按最短时间排序
}
int a[maxn], b[maxn], n;
int ans[maxn];//最佳调度顺序
int main(){
cin >> n;
for(int i = 1; i <= n; i ++){
job[i].index = i;//序号
cin >> a[i];//在A上加工的时间
}
for(int i = 1; i <= n; i ++){
cin >> b[i];//在B上加工的时间
job[i].time = min(a[i], b[i]);//获取A和B上加工的最短时间
}
sort(job + 1, job + n + 1, cmp);//按时间排序
int x = 1, y = n;
for(int i = 1; i <= n; i ++){
if(job[i].time == a[job[i].index]){//如果在A的时间更短
ans[x ++] = job[i].index;//A时间短的往前面塞
}else{
ans[y --] = job[i].index;//B时间段的往后面塞
}
}
//记住,ans里存的是下标
int fa = a[ans[1]];//fa为i在车间A加工完需要的时间
int fb = fa + b[ans[1]];//fb为i在车间B加工完需要的时间
for(int i = 2; i <= n; i ++){
//i开始在车间B加工时需要满足两个条件:
//一个是i在A加工完成,另一个是i-1在B加工完成
//看看谁最晚,有一个没好的话,i都没法在车间B加工。
fb = max(fa + a[ans[i]], fb) + b[ans[i]];
fa += a[ans[i]];
}
cout << fb << endl;//加工总时长
for(int i = 1; i <= n; i ++) cout << ans[i] << ' ';
return 0;
}