动态规划和贪心算法分析(装配线调度、最小生成树)

来源:互联网 发布:网络国际电话 编辑:程序博客网 时间:2024/06/06 13:11

        本文主要从问题分析的角度介绍动态规划和贪心算法,文中不涉及代码。通过装配线调度问题和最小生成树问题,说明怎样运用动态规划和贪心算法解决问题。

1    装配线调度问题

1.1   问题描述

       如下图所示,某个工厂有两条装配线,每条装配线上有n个装配站,装配站S_{i,j}表示第i条装配线上的第j个装配站,其中i=1,2j=1,2,…,n。装配站S_{1,j}与装配站S_{2,j}具有相同的作用,其中a_{i,j}表示装配站S_{i,j}完成装配所需要的时间,在同一条装配线上,商品从上一个装配站转移到下一个装配站不需要时间,但是如果商品从一条装配线换到另一条装配线上则需要时间t,如图所示。一件商品从开始端进入装配线的时间分别是e_1,e_2。然后必须依次经过没个装配站进行装配,然后在结束端离开装配线的时间分别是x_1,x_2。带求解问题是应该确定在装配线1内选择哪些站,在装配线2内选择哪些站,才能使商品通过工厂的时间最小。

1.2   问题分析

        首先,这是一个做选择类的问题,而对于做选择的所有问题我们都可以从穷举的角度去分析问题。我们最终要选择一个装配路线,使得商品的装配时间最少,而在每一个装配站都有两个选择(装配线1,还是装配线2)。所以要穷举所有的装配路线,一共有2^n种选择,那么算法的运行时间复杂度是O(2^n),当n很大时显然是不可取的。

        现在,从动态规划的角度去分析这个问题。关于动态规划,要记住一点,就是动态规划是以空间换时间的。接下来我们就需要好好理解这个话。首先要明确该问题中的目标值是什么。从问题中知道,该问题是选择装配路线,使得商品的装配时间最少。所以,很明显目标位装配的时间T。T(1,i)表示经过装配线1上第i个装配站后的装配时间,T(2,i)表示经过装配线2上第i个装配站的装配时间。所以可以得到如下的递归公式。

        可见,在求第i时刻的最优解T(1,i)和T(2,i)时,需要i-1时刻的最优解T(1,i-1)和T(2,i-1)。这里出现了重叠子问题,所以可以将子问题的解以表的形式保存起来,那么以后要用的时候不用重新计算,只要查表就行了,这就是所谓的以空间换时间。

1.3   具体实例

 

        在求解问题最优解的过程中,首先求解子问题的最优解,并将结果保存起来。在求解过程中,需要两张表来保存结果。T表保存目标值,P表保存路径。

第一步,初始化两张表。

T表i123456T(1,i)      T(2,i)      P表i123456P(1,i)000000P(2,i)000000

第二步,根据递归公式计算。i=1时。

T表i123456T(1,i)9     T(2,i)12     P表i123456P(1,i)100000P(2,i)200000

i=2时,

T表i123456T(1,i)918    T(2,i)1216    

P表i123456P(1,i)110000P(2,i)210000

i=6时,

T表i123456T(1,i)91820243235T(2,i)121622253037P表i123456P(1,i)112112P(2,i)212122

第三步,根据T表和P表得到最优解。

2    最小生成树问题

2.1   问题描述

        对于一个无向连通图G=(V,E),其中V为图的顶点集合,E为图的边集合。对图中每一条边(u,v),都有一个权值w(u,v)表示连接u和v的代价,找出一个E的子集T,连接所有的顶点,并且保证权值和w(T)最小。

2.1    问题分析

        首先,这个问题也是关于选择的问题。问题的解为一系列边的集合,并且满足两个条件:保证图的连通性;权值和最小。所以最原始最简单的方法就是穷举,然后判断是否满足着两个条件。假设图的有e条表,那么E的子集个数为2^e种情况,因此算法的运行时间复杂度为O(2^e),当e很大时,这显然是不行的。

        现在从动态规划的角度来分析这个问题,找出最优子结构。这个问题要优化的目标值为树的权值和W。可以从顶点和边两方面来找递归公式。

        从顶点出发,将图中的顶点排序{V1,V2,,Vi,Vn}W(i)表示连接{V1,V2,,Vi}的最小生成树的权值。其中如果边(ij)不存在,则w(i,j)为无穷大。

可以采用“剪切-粘贴”法,证明该递归公式的重要性。证明比较简单,这里就不在证明了。这个算法的实现也就是经典的Prim算法了。

       从边出发,将图中的边按照权值由小到大排序,排序结果为{E1,E2,,Ei,,Ee}。每条边Ei在最优解中只有两种选择:被选与不被选。W(i)表示判断表Ei是否被选后,树的权值。则递归公式可表示为:

        所谓的连通性是否改变就是有没有新的顶点加进去。同样采用“剪切-粘贴”法可证明该递归公式的重要性,这个递归公式的实现也就是Kruskal算法了。

          众所周知,Prim算法和Kruskal算法都是贪心算法,而上面都分析都是从动态规划的角度去分析问题的。下面就看看动态规划与贪心算法,分析问题时的不同。

         认真观察上面的递归公式可以看出,装配线调度问题的递归解中出现了重叠子问题T(1,i-1)T(2,i-1),而最小生成树时,要计算W(i),只要知道W(i-1)即可,没有重现重叠子问题。换言之,也就是最小生成树问题的求解,只需要一个子问题,再进行相关处理就行了。所以当动态规划的递归解满足这个特性的时候,就可以采用贪心算法来解决。贪心算法是动态规划的一个特例,能用动态规划解决的问题,当满足一定条件的时候就可以用贪心算法解决。

3    动态规划与贪心算法分析总结

        动态规划是一种用空间换时间,从而降低算法的时间复杂度的算法。适合采用动态规划的最优问题需要两个要素:最优子结构和重叠子问题。

最优子结构

        如果一个最优解中包含子问题的最优解,则该问题具有最优子结构。现在问题的关键是如何判断一个最优问题是否有最优子结构,以及给出一个最优子结构,怎么判断是最优解的子结构。这两个问题其实是一个问题。要解决这两个问题,一般我们从问题本身出发,采用自顶向下的方法进行分析。首先,根据推理或经验等给出一个递推解的结构,再证明该结构为该最优问题的最优子结构,常用的证明方法有“剪贴”技术。

        在寻找最优子结构时,可以遵循一种共同的模式:

1)、问题的一个解,可以是做一个选择。例如,选择一个前一个装配线转配站;或者选择一个下标以在该位置分裂矩阵链。做这种选择会得到一个或多个有待解决的子问题。

2)、假设对一个给定的问题,已知的是一个可以导致最优解的选择。不必关系如何确定这个选择,尽管假定它是已知的。然后要确定哪些子问题随之变化,以及如何最好地描述所得到的的子问题空间。

        为了描述子问题空间,可以遵循这样一条有效的经验规则,就是尽量保持这个空间简单,然后在有需要的时候再扩充它。

        最优子结构在问题域中以两种方式变化:

1)、有多个子问题被使用在原问题的一个最优解中

2)、在决定一个最优解中使用哪些子问题时有多个选择

       动态规划以自底向上的方式利用最优子结构。也就是说,首先找到子问题的最优解,解决子问题,然后找到问题的一个最优解。寻找问题的一个最优解需要在子问题中做出选择,即选择将用哪一个来求解问题。问题的代价通常是子问题的代价加上选择本来带来的开销。贪心算法与动态规划有很多相似之处。特别地,贪心算法适用的问题也具有最优子结构。贪心算法与动态规划有一个显著的区别,就是在贪心算法中,是以自顶向下的方式使用最优子结构。贪心算法会先做选择,在当时看起来是最优的选择,然后再求解一个结果子问题,而不是先寻找子问题的最优解,然后在做选择。 

 

解决这类问题的一步步骤

1、判断问题是否为选择类问题。

2、找出目标值。

3、找最优子结构,写出递归公式。

根据递归公式判断是否有重叠子问题,有重叠子问题,采用动态规划解决,无重叠子问题采用贪心算法解决。