您的位置:首页 > 其它

动态规划之装配线调度

2014-06-08 13:54 393 查看
在看这张之前,最好看看我写的动态规划详解,里面都是讲理论基础,我下面的分析都是在此基础上进展的。

题目:

装配一辆汽车,有两条装配线分别有n个装配点,每条装配线在进出所花时间为e[i],x[i] (i=0,1),每个装配点所需时间a[i][j](i=0,1;j=0,1,...,n-1),从一条装配线i的第j个装配点到另一条装配线的第j+1个装配点所需时间t[i][j]。



DP算法的设计可以分为四个步骤:

①.描述最优解的结构。

②.递归定义最优解的值。

③.按自底而上的方式计算最优解的值。

④.由计算出的结果创造一个最优解。

下面用上面的四步来解题:

①.描述最优解的结构。

最后的出口(1,n)从第(1,n-1)位置或(2,n-1)来,出口(2,n)类似。那好,这样一次划分后,是否具有最优子结构问题?具有最优子结构:一个问题的最优解包含了子问题的一个最优解。正如这个题中,找出通过装配站S(i,j)的最优解,包含了找出通过S(1,j-1)或S(2,j-1)的一个最优解。转化成了,为了解决这个问题(寻找通过任一条装配线上的j的最快路线),我们解决其子问题(寻找通过两条装配线上的j-1的最快路线),原问题就能的解。

②.递归定义最优解的值。

第一步分析了最优解是如何拆分的,第二步就是用来组成最优解。

装配线问题:根据题意,可以写出f(i)与f(i-1)之间的关系。

先剥离边界性条件差异,我们得到如下递归式:





然后处理边界性问题

出口时,应该求解f1
+x1,f2
+x2
。然后选出其中的最小值求解。

入口时,也有条件:



因此得到两个方程组和一个结果方程





方程有了,第二步也就算结束了。

③.按自底而上的方式计算最优解的值。

如果单纯根据表达式求解的话,需要用到递归,问题是解决了,但时间复杂度是O(2^n)。这明显是不理想的。但对于动态规划问题,通常采用自底向上的方式,需要建立数组来保持。那么这里就有个问题,数组保存哪些值呢?利用数组就是为了防止递归带来的时间消耗,因此数组保存的是要递归时的返回值。也就是递归表达式中的f1[n-1]以及f2[n-2]。

有了这样的数组,将i从1->n增长,一步一步求解。

④.由计算出的结果创造一个最优解。

通常只用求解最优解的话,是不需要这一步的。但要给出方案,就要保存路径信息。只需要额外设置数组即可。

如果按照书中的话,设计两个数组li[j]。i=1/2,j表示第j个装配站,l1[j]保存1/2,含义是到达这个点的话,最短路径是从1线的j-1过来的还是从2线的j-1过来的。整体的含义表示,到达i线上的j站点来自于哪个线上的j-1。但是求出口时,要有个统一的入口设一个变量L*,那么根据f1
+x1和f2
+x2的大小决定L*为1还是为2。

注意:一开始考虑这里附设一个数组就可以了,将L[j]存储从哪个结点过来的,这样是不合理的,l1[]和l2[]数组是不能合并的。

代码如下:

int n;                 // 一个装配线上有n个装配站
int e1, e2;            // 进入装配线1,2需要的时间
int x1, x2;            // 离开装配线1,2需要的时间
int t[3][100];         // t[1][j]表示底盘从S[1][j]移动到S[2][j+1]所需时间,同理t[2][j]
int a[3][100];         // a[1][j]表示在装配站S[1][j]所需时间
int f1[100], f2[100];  // f1[j], f2[j]分别表示在第一/第二条装配线上第j个装配站的最优解
int ln1[100], ln2[100];// ln1[j]记录第一条装配线上,最优解时第j个装配站的前一个装配站是第一条线还是第二条线上
int f, ln;             // 最优解是,f代表最小花费时间,ln表示最后出来时是从装配线1还是装配线2

void DP()
{
f1[1] = e1 + a[1][1];
f2[1] = e2 + a[2][1];
for(int j=2; j<=n; ++j){
// 处理第一条装配线的最优子结构
if(f1[j-1] + a[1][j] <= f2[j-1] + t[2][j-1] + a[1][j]){
f1[j] = f1[j-1] + a[1][j];
ln1[j] = 1;
}else{
f1[j] = f2[j-1] + t[2][j-1] + a[1][j];
ln1[j] = 2;
}
// 处理第二条装配线的最优子结构
if(f2[j-1] + a[2][j] <= f1[j-1] + t[1][j-1] + a[2][j]){
f2[j] = f2[j-1] + a[2][j];
ln2[j] = 2;
}else{
f2[j] = f1[j-1] + t[1][j-1] + a[2][j];
ln2[j] = 1;
}
}
if(f1
+ x1 <= f2
+ x2){
f = f1
+ x1;
ln = 1;
}else{
f = f2
+ x2;
ln = 2;
}
}

void PrintStation()
{
int i= ln;
printf("line %d,station %d",i,n);

for(int j=n; j>=2; --j){
if(i == 1)
i = ln1[j];
else
i = ln2[j];
printf("line %d ,station %d",i,j-1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: