背景 加工生产调度
题目描述
某工厂收到了 n 个产品的订单,这 n 个产品分别在 A、B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工。
某个产品 i 在 A、B 两车间加工的时间分别为。怎样安排这 n 个产品的加工顺序,才能使总的加工时间最短。
这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A、B 两车间加工完毕的时间。
分析
对于这个问题,我们的直观想法就是使ai尽可能的短,bi尽可能的长,这样当我们再进行bi的同时a(i+1)就可以开始运作,就可以省去向下面图4的情况第二台已经空出来了,可是我还得等待a(i+1)加工完毕。
下面我们通过一些图片来解析一下这个题意
示例:有3个作业如下图所示
于是共有6种调度安排:
对于方案 4, 请注意,b2结束后并不能立即进行b3的工作,因为题目已经说了要等a3加工结束才能进行b3的加工
其中方案3总时间最短。
现在我们来分析一下最差方案,对于方案4,使其成为最差的主要原因是因为出现了等待的时间,a3加工时间实在是太长了,但是我们必须等他结束了才能进行b3。然后我们对其进行优化,是否调换一下前后1,2两个作业或者2,3两个作业的先后顺序就可以缩短时间呢。
于是我们引出了关键思路: 如果对换“相邻”的两个作业会不会缩短时间?如果能我们就对换
假定 (t0表示前面加工需要的时间)后 M2 才开始空闲,但作业1在机器2的实际开始时刻应该是
。因为我们必须等a1加工完毕了我们才能进行b1的加工,也就是说当
<a1的时候会出现空格时间,如上图4,
,实际运行开始运行时间为
对作业1之后的作业2而言,有四种情况
我们分析一下在第二台机器上的加工时间,首先b2是不可能超过a2的,所以我们可以直接加上b2,然后只需考虑前面,由上图便可得到以下等式
- 在 M1 上的最早开始时间是
;
- 在 M2 上的最早开始时间是
。
- 使用我们总的加工时间就是
当作业1和作业2的次序对换时, Δ 不变化,此时对作业2之后的作业而言:
- 在 M1 上的最早开始时间是
;(没有变化)
- 在 M2 上的最早开始时间是
。
- 使用我们总的加工时间就是
下面我们分四种情况讨论一下交换前和交换后,这两个作业在 M2 上都完成的最早时间:
首先我们记表示的是
之间的最小值是
① 。此时有
,
于是 (求的是最大值,所以可以直接把小的去掉)
求出的最大值都是+b1+b2的,所以换序无妨
又,
(这里说简单点就是a1<b1,a1<a2)
可得
因此 ,即交换次序不会使情况变好。
② 。类似于①,自证,可知
,即交换次序不会是其变差。
(取得到等号所以不能直接说变好)
③ 。 此时有
,
于是。
又 ,
可得。
即,即交换次序不会使情况变差。
④ 。类似③,可得,即交换次序不会使情况变好。
以上分析了什么情况下对换“相邻”的两个作业至少不会使情况变差。
因此我们可以从局部到整体,分析如何确定加工顺序。
计算 ,有两种情况:
① 这个最小值是某个,那么如果它不是第一个被加工的,就可以根据②将它与前面相邻的任务次序对换,而总时间不会变长(还有可能变短)。不断这样进行下去,直到它成为第一个被加工的。把它放到该放的位置,以后就不用考虑它了。
② 这个最小值是某个 ,那么如果它不是最后一个被加工的,就可以根据③将它与后面相邻的任务次序对换,而总时间不会变长(还有可能变短)。不断这样进行下去,直到它成为最后一个被加工的。把它放到该放的位置,以后就不用考虑它了。
而②和③,就是所称的“Johnson不等式”:
如果作业 i 和 j ,i在j前面,满足 ,则称作业 i 和 j 满足Johnson不等式。
代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1005;
int n,ans;
struct node
{
int a,b,c;//分别代表作业1和作业2,还有对应编号,
//i表示不了,因为后面要排序我们先记录一下
bool operator<(const node &v)
{
return min(a,v.b)<min(b,v.a);//Johnson不等式,注意小于号左边的是前一个的b作业与后一个
的a作业
}
}d[N];
int main()
{
int n;cin>>n;
for(int i=1;i<=n;i++)
{
cin>>d[i].a;d[i].c=i;
}
for(int i=1;i<=n;i++)
cin>>d[i].b;
sort(d+1,d+1+n);
int x=0,y=0;
for(int i=1;i<=n;i++)
{
x+=d[i].a;
y=max(x,y)+d[i].b;//首先无论如何都需要等到ai结束才能进行bi,
//其次如果ai结束了bi-1,还没结束我们依然要等,所以取其中最大值
}
cout<<y<<"\n";
for(int i=1;i<=n;i++)
cout<<d[i].c<<" ";
return 0;
}