• 算法导论-动态规划-装配线调度


      动态规划(dynamic programming)是通过组合子问题的解而解决整个问题的。分治算法是指将问题划分为一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原问题的解。动态规划适用于子问题不是独立的情况,也就是各子问题包含公共的子子问题。在这种情况下,若用分治法则会做许多不必要的工作,即重复地求解公共的子子问题。动态规划对每个子子问题只求解一次,将结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案。

      动态规划通常应用于最优化问题。此类问题可能有很多种可行解,每个解有一个值,我们希望找出一个具有最优(最大或最小)值的解,称这样的解为该问题的一个最优解(而不是确定的最优解),因为可能存在多个取最优解的值。

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

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

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

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

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

    装配线调度

    Colonel汽车公司在有两条装配线的工厂内生产汽车。一个汽车底盘在进入每一条装配线后,在一些装配站中会在底盘上安装部件,然后,完成的汽车在装配线的末端离开。每一条装配线上有n个装配站,编号为j=1,2,…,n。将装配线i(i为1或2)的第j个装配站表示为。装配线1的第j个站()和装配线2的第j个站()执行相同的功能。然而,这些装配站是在不同的时间建造的,并且采用了不同的技术,因此,每个站上所需的时间是不同的,即使在两天不同装配线相同位置的装配站上也是这样。把在装配站上所需的装配时间记为。底盘进入装配线i的进入时间为ei,装配完的汽车离开装配线i的离开时间为xi

    正常情况下,一旦一个底盘进入一条装配线后,它只会经过该条装配线。在相同的装配线中,从一个装配站到下一个装配站所花的时间可以忽略。偶尔会来一个特别急的订单,客户要求尽可能快地制造这些汽车。对这些加急的订单,底盘仍然依序经过n个装配站,但工厂经理可以将部分完成的汽车在任何装配站上从一条装配线移到另一条装配线上。把已经通过装配站的一个底盘从装配线i移走所花的时间为,其中i=1,2,j=1,2,…,n-1(因为在第n个装配站后,装配已经完成)。问题是要确定在装配线1内选择哪些站以及在装配线2内选择哪些站,以使汽车通过工厂的总时间最小。

    解题报告:

    步骤1:描述最优解的特征。

    对于装配线调度问题,一个问题(找出通过装配站的最快路线)最优解包含了子问题(找出通过的最快路线)的一个最优解。称这个性质为最优子结构,这是是否可以应用动态规划方法的标志之一。可以利用子问题的最优解来构造原问题的一个最优解。

    步骤2:一个递归的解。

    利用子问题的最优解来递归定义一个最优解的值。选择在两条装配线上通过装配站j的最快路线问题作为子问题,j=1,2,…,n。

    表示一个底盘从起点到装配站的最快可能时间,为底盘通过工厂的所有路线的最快时间,则,其中。进一步得出:

    步骤3:计算最快时间。

    整个过程花费时间

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

    参考代码如下:

      1 #include <iostream>
      2 using namespace std;
      3 
      4 typedef struct  
      5 {
      6     int **a;
      7     int **t;
      8     int *e;
      9     int *x;
     10     int n;
     11 }LineCondition;
     12 
     13 void FastestWay(const LineCondition *line, int **&l, int **&f, int &ftotal, int &lend)
     14 {
     15     int n = line->n;
     16 
     17     f[0][0] = line->e[0] + line->a[0][0];
     18     f[1][0] = line->e[1] + line->a[1][0];
     19 
     20     for (int i = 1; i < n; ++i)
     21     {
     22         if (f[0][i - 1] + line->a[0][i] <= f[1][i - 1] + line->t[1][i - 1] + line->a[0][i])
     23         {
     24             f[0][i] = f[0][i - 1] + line->a[0][i];
     25             l[0][i] = 1;
     26         }
     27         else
     28         {
     29             f[0][i] = f[1][i - 1] + line->t[1][i - 1] + line->a[0][i];
     30             l[0][i] = 2;
     31         }
     32 
     33         if (f[1][i - 1] + line->a[1][i] <= f[0][i - 1] + line->t[0][i - 1] + line->a[1][i])
     34         {
     35             f[1][i] = f[1][i - 1] + line->a[1][i];
     36             l[1][i] = 2;
     37         }
     38         else
     39         {
     40             f[1][i] = f[0][i - 1] + line->t[0][i - 1] + line->a[1][i];
     41             l[1][i] = 1;
     42         }
     43     }
     44 
     45     if (f[0][n - 1] + line->x[0] <= f[1][n - 1] + line->x[1])
     46     {
     47         ftotal = f[0][n - 1] + line->x[0];
     48         lend = 1;
     49     }
     50     else
     51     {
     52         ftotal = f[1][n - 1] + line->x[1];
     53         lend = 2;
     54     }
     55 }
     56 
     57 void PrintStations(int **l, int lend, int n)
     58 {
     59     int *a = new int[n];
     60     int i = lend - 1;
     61     int m = n;
     62     a[--m] = i + 1;
     63 
     64     for (int j = n - 1; j > 0; --j)
     65     {
     66         i = l[i][j] - 1;
     67         a[--m] = i + 1;
     68     }
     69 
     70     for (int i = 0; i < n; ++i)
     71     {
     72         cout << "line " << a[i] << ", station " << i + 1 << endl;
     73     }
     74     
     75     delete [] a;
     76 }
     77 
     78 
     79 int main(void)
     80 {
     81     LineCondition line;
     82 
     83     cout << "请输入装配站数目n:";
     84     cin >> line.n;
     85 
     86     line.a = new int *[2];
     87     for (int i = 0; i < 2; ++i)
     88     {
     89         line.a[i] = new int [line.n];
     90     }
     91     for (int i = 0; i < 2; ++i)
     92     {
     93         cout << "请输入装配线" << i + 1 << "上每个装配站耗费时间a[i][j]:";
     94         for (int j = 0; j < line.n; ++j)
     95         {
     96             cin >> line.a[i][j];
     97         }
     98     }
     99 
    100     line.t = new int *[2];
    101     for (int i = 0; i < 2; ++i)
    102     {
    103         line.t[i] = new int [line.n - 1];
    104     }
    105     for (int i = 0; i < 2; ++i)
    106     {
    107         cout << "请输入装配线t[" << i << "][j]:";
    108         for (int j = 0; j < line.n - 1; ++j)
    109         {
    110             cin >> line.t[i][j];
    111         }
    112     }
    113 
    114     line.e = new int [2];
    115     cout << "请输入e1,e2:";
    116     cin >> line.e[0] >> line.e[1];
    117 
    118     line.x = new int [2];
    119     cout << "请输入x1,x2:";
    120     cin >> line.x[0] >> line.x[1];
    121 
    122     int **l = new int *[2];
    123     int **f = new int *[2];
    124     for (int i = 0; i < 2; ++i)
    125     {
    126         l[i] = new int [line.n];
    127         f[i] = new int [line.n];
    128     }
    129 
    130     int lend, ftotal;
    131     FastestWay(&line, l, f, ftotal, lend);
    132     PrintStations(l, lend, line.n);
    133 
    134     return 0;
    135 }

    按照如下图片输入相关数据:

    测试结果如下:

  • 相关阅读:
    线上崩溃... MediaPlayerNative: error (1, -2147483648)
    Android Notification cancel和cancelAll方法无效问题
    Android ButterKnife 找不到符号
    Android日历组件
    Android dimen适配
    Android View的invalidate()原理
    Android Camera坐标系三维图及正向绕行方向
    Android 自定义多选的 Spinner
    Android中PorterDuff.Mode【转】
    java面向对象的注意点2
  • 原文地址:https://www.cnblogs.com/mengwang024/p/4295389.html
Copyright © 2020-2023  润新知