装配线调度
问题:一个工厂有两条装配线a1, a2,每条装配线有n个装配站,每个编号对等的装配站功能相同。机器只要依次通过编号为1,2,...,n的装配站即可加工完成。已知两条装配线各个装配站装配所需的时间即a1,1,a1,2,...,a1,n, a2,1,a2,2,...,a2,n, 进入装配线所需时间e1,e2,离开装配线所需时间x1,x2。有时候为了加快装配进度,可以将部分完成的机器从一条装配线移到另一条装配线,所需时间分别为t1,1,t1,2,...,t1,n-1, t2,1,t2,2,...,t2,n-1. 求机器制造所需的最短时间。
算法基本思路:
1.计算最优解即最短时间;
要求最短时间,可以看作求到达装配s1,n, s2,n的最短时间。要到达s1,n,有两种可能。
(1)从s1,n-1直接到s1,n;
(2)从s2,n-1经过t2,n-1到达s1,n。
对于s2,n,也是类似情况。
不难看出,几乎对于所有站点都存在这个性质(起始站点除外)。满足最优子结构,和重叠子问题(对等编号的站点对前一站点的最优时间重复使用),可用动态规划法。
设f[1][i]表示到达装配线1上 i 号站点所需的最短时间,f[2][i]表示到达装配线2上 i 号站点所需的最短时间。
f[1][1]初始化为e[1] + a[1][1],f[2][1]初始化为e[2] + a[2][1]。则有,
f[1][i] = min{f[1][i-1] + a[1][i], f[2][i-1] + t[2][i-1] + a[1][i]}, (2<= i <= n)
f[2][i] = min{f[2][i-1] + a[2][i], f[1][i-1] + t[1][i-1] + a[2][i]}, (2<= i <= n)
此时易得最小时间 t = min{f[1][n] + x[1], f[2][n] + x[2]}。
2.构造获得最短时间的路线。
在计算最短时间的基础上,多开一个记录表 l[1][i] 表示 到达装配线1上 i 号站点的前一个站点, l[2][i] 表示 到达装配线2上 i 号站点的前一个站点。
从最后一个站点逆推可得整条路线。
public class AssemblyLineScheduling{ public static String fastestWay(int[][] a, int[][] t, int[] e, int[] x){ /* a means the cost time of assembly station t means the transform time betweeen different line e means the time of enter assembly line x means the time of exit assembly line return the cost time of the fastest way */ int n = a[0].length; int[][] f = new int[2][n]; int[][] l = new int[2][n-1]; //init f[0][0] = a[0][0] + e[0]; f[1][0] = a[1][0] + e[1]; //dynamic programming for(int i = 1; i < n; i ++){ if(f[0][i-1] + a[0][i] < f[1][i-1] + t[1][i-1] + a[0][i]){ f[0][i] = f[0][i-1] + a[0][i]; l[0][i-1] = 0; } else{ f[0][i] = f[1][i-1] + t[1][i-1] + a[0][i]; l[0][i-1] = 1; } if(f[0][i-1] + t[0][i-1] + a[1][i] < f[1][i-1] + a[1][i]){ f[1][i] = f[0][i-1] + t[0][i-1] + a[1][i]; l[1][i-1] = 0; } else{ f[1][i] = f[1][i-1] + a[1][i]; l[1][i-1] = 1; } } int r; int p; //build the path if(f[0][n-1] + x[0] < f[1][n-1] + x[1]){ r = f[0][n-1] + x[0]; p = 0; } else{ r = f[1][n-1] + x[1]; p = 1; } String result = "line " + p + ", station " + (n-1) + "\n" + r; for(int i = n-2; i >= 0; i --){ result = "line " + l[p][i] + ", station " + i + "\n" + result; p = l[p][i]; } return result; } public static void main(String[] args) { //Unit Testing int[][] a = {{7, 9, 3, 4, 8, 4}, {8, 5, 6, 4, 5, 7}}; int[][] t = {{2, 3, 1, 3, 4}, {2, 1, 2, 2, 1}}; int[] e = {2, 4}; int[] x = {3, 2}; System.out.println(fastestWay(a, t, e, x)); } }