动态规划 - 装配线调度问题


1         动态规划介绍

动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。

动态规划通常应用于最优化问题。此类问题可能有很多种可行解。每个解有一个解,而我们希望找出一个最优解(最大值或最小值)。

动态规划算法的设计可分为如下4个步骤:

(1)描述最优解的结构;

(2)递归定义最优解的值;

(3)按自底向上的方式计算最优解的值;

(4)由计算出的结果构造一个最优解。

第1~3步构成问题的动态规划解得基础,第4步在只要求计算最优解的值时可以略去。如果的确做了第4步,则有时要在第3步的计算中记录一些附加信息,要构造一个最优解变得容易。

 

2         装配线调度问题描述

一个找出通过工厂装配线的最快方式的制造问题。共有两条装配线,每一条装配线上有n个装配站,编号为j = 0, 1, … , n - 1。装配线i(i = 0或1),在装配站S[i][j]上所需的装配时间记为a[i][j]。一个汽车底盘进入工厂,然后进入装配线i的进入时间为e[i],在通过一条线的第j个装配站后,这个底盘来到任一条线的第(j + 1)个装配站。如果留在相同的装配线上,则没有移动的开销;如果在装配站S[i][j]后,它移动到了另一条线上,则花费时间t[i][j]。在离开一条线的第n个装配站后,完成的汽车离开装配线i的离开时间为x[i] 。

 

f[i][j]:表示底盘从起点到装配站S[i][j]的最快可能时间。

t[i][j]:表示底盘从装配站S[i][j]移到另一条装配线花费的时间。

a[i][j]:表示底盘在装配站S[i][j]停留的时间。

e[i]:表示底盘进入装配线i的时间。

x[i]:表示底盘完成安装离开装配线花费的时间。

 

3         问题分析

步骤1:通过工厂最快线路的结构

通过装配站S[1][j]的最快线路只能是以下二者之一:

(1) 通过装配站S[1][j-1]的最快线路,然后直接通过装配站S[1][j]。

(2) 通过装配站S[2][j-1]的最快线路,从装配线2移动到装配线1,然后通过装配站S[1][j]。

当然,通过装配站S[2][j]的最快线路也只能是以下二者之一:

(1) 通过装配站S[2][j-1]的最快线路,然后直接通过装配站S[2][j]。

(2) 通过装配站S[1][j-1]的最快线路,从装配线1移动到装配线2,然后通过装配站S[1][j]。

为了解决装配线调度问题,即寻找通过任意一条装配线上的第j个装配站的最快路线,就可以解决装配线调度问题。

 

步骤2:一个递归的解

假设已经完成了汽车的装配,那么这些路线的较快者即是:

fast =min{f[1][n] + x[1], f[2][n] + x[2]};

初值为:

f[1][1] =e[1] + a[1][1];

f[2][1] =e[2] + a[2][1];

考虑f[i][j](j>1)的计算,很明显:

f[1][j] =min{f[1][j-2] + a[1][j], f[2][j-1] + t[2][j-1] + a[2][j]};

f[2][j] =min{f[2][j-2] + a[2][j], f[1][j-1] + t[1][j-1] + a[1][j]};

 

步骤3:计算最快时间

整个过程花费时间为O(n);

 

步骤4:构造通过工厂的最快路线

为了构造通过工厂的最快路线,需要构造一个新的数组l[i][j],其值为(1或者2),表示装配线编号,装配站j-1被通过S[i][j]的最快路线所使用。

 

4         实例与编码

1. 实例

e[1]=2, e[2]=4;

x[1]=3; x[2]=2;

a[i][j]的值如下表:

j

1

2

3

4

5

6

a[1][j]

7

9

3

4

8

4

a[2][j]

8

5

6

4

5

7

t[i][j]的值如下表:

j

1

2

3

4

5

t[1][j]

2

3

1

3

4

t[2][j]

2

1

2

2

1

 

2. 编码实现

针对具体问题的实现代码

 

/**
 * fastway - 求解装配线最快线路的时间
 * Param.:
 *      @a[][]: 在装配线i上第j个装配站停留的时间(i=0,1;j=0...(n-1))
 *      @t[][]: 从装配线i上第j-1个装配站移动到另一个装配线的时间
 *      @e[]:   进入装配线i的时间
 *      @x[]:   在装配线i上最后一个装配站离开的时间
 *      @n:     装配站的个数
 *      @f[][]: 经过装配线i上第j个装配站时的最快时间(被赋值)
 *      @flag[][]: 通过装配站j的最快线路的装配站j-1所在的装配线(被赋值)
 *      @fast: 最快线路的时间(被赋值)
 *      @falg: 最快线路的最后一个装配站所在的装配线(被赋值)
 * return:
 *      无
 */
void fastway(int a[][6], int t[][5], int e[], int x[], int n,
        int f[][6], int flag[][6], int *fastp, int *lastflagp)
{
    int j, fast, lastflag;
 
    f[0][0] = e[0] + a[0][0];
    f[1][0] = e[1] + a[1][0];
    for (j = 1; j < n; j++)
    {
        /* 计算f[0][j]和flag[0][j] */
        if ((f[0][j - 1] + a[0][j]) <= (f[1][j - 1] + t[1][j - 1] + a[0][j]))
        {
            f[0][j] = f[0][j - 1] + a[0][j];
            flag[0][j] = 0;
        }
        else
        {
            f[0][j] = f[1][j - 1] + t[1][j - 1] + a[0][j];
            flag[0][j] = 1;
        }
        /* 计算f[1][j]和flag[1][j] */
        if ((f[1][j - 1] + a[1][j]) <= (f[0][j - 1] + t[0][j - 1] + a[1][j]))
        {
            f[1][j] = f[1][j - 1] + a[1][j];
            flag[1][j] = 1;
        }
        else
        {
            f[1][j] = f[0][j - 1] + t[0][j - 1] + a[1][j];
            flag[1][j] = 0;
        }
    }
 
    /* 计算最优解fast和flag(表示从哪个装配线上的n装配站完成) */
    if ((f[0][n - 1] + x[0]) <= (f[1][n - 1] + x[1]))
    {
        fast = f[0][n - 1] + x[0];
        lastflag = 0;
    }
    else
    {
        fast = f[1][n - 1] + x[1];
        lastflag = 1;
    }
 
    *fastp = fast;
    *lastflagp = lastflag;
}
/**
 * printway - 求解装配线最快线路的时间
 * Param.:
 *      @flag[][]: 通过装配站j的最快线路的装配站j-1所在的装配线(被赋值)
 *      @falg: 最快线路的最后一个装配站所在的装配线(被赋值)
 *      @n:     装配站的个数
 * return:
 *      无
 */
void printway(int flag[][6], int *lastflagp, int n)
{
    int i, j;
    i = *lastflagp;
    printf("line:%d, station:%d\n", i, n);
    for (j = n; j >= 1; j--)
    {
        i = flag[i][j];
        printf("line:%d, stations:%d\n", i, (j - 1));
    }
}


 

posted on 2012-03-17 11:39  YoungerChina  阅读(421)  评论(0编辑  收藏  举报

导航