参考《算法导论第二版P222页)
一,如何把现实的问题转变成数学问题?即数学建模的思路?
1,问题描述:现有一组相互竞争的活动,如何调度能够找出一组最大的活动(活动数目最多)使得它们相互兼容?
2,问题转化:
首先,按活动的结束时间单调递增进行排序。那么,为什么要按结束时间排序呢?这个问题留到后面解释。
其次,定义合适的问题子空间,即定义集合S(i,j)。问题子空间描述的是现实生活中的问题,而集合S(i,j)则是数学概念,通过某种方式定义一个合适的集合将问题子空间的解转化为集合的解(即求出集合中符合某种条件的所有元素)。
3,那么问题来了,怎样才能让定义的这个集合问题能够描述现实问题呢?----
a,将S(i,j)中元素表示成与活动a(i)、a(j)兼容的活动
b,将活动a(1)、a(2)……a(i)、a(i+1)、……a(j)、a(j+1)……a(n) 按照结束时间单调递增排序!每个集合元素有一个特征:有开始时间和结束时间。
这就是为什么要按结束时间单调递增排序的原因,因为只有这样,才能够成功的建模,将现实问题转化成数学问题。
当定义的集合中的元素(活动)满足了这两个因素之后,就可以将子问题空间(从a(1)、a(2)……a(i)、a(i+1)、……a(j)、a(j+1)……a(n)活动中选出最大兼容活动集合)
转化成
数学上的集合问题(求解集合S(i,j)的元素中满足开始时间和结束时间不相互冲突的最多的元素个数)
4,如何证明子问题S(i,j)的解是最优的?
剪贴技术 即 反证法。建模出来的集合的性质,它可以将S(i,j)的最优解分成S(i,k)S(k,j)的最优解!
5,如何根据子问题的解构造出原问题的解?
构造虚构的活动 a(0)和a(n+1)。那么,S(0,n+1)就表示原问题的解!
6,写出问题的解的数学表达式
数学表达式见 《算法导论第二版》P244 上。
二,活动选择的贪心策略及证明此贪心策略的正确性
1,贪心策略:先将活动按结束时间单调递增进行排序,并且优先选择结束时间最早的活动。具体操作如下:
a,设已排好序的各个活动构成的集合为S(0,n+1),最大兼容活动集合为A,A初始为空
b,在S(0,n+1)中选择结束时间第一早(最早)的活动,记为a1,A = A U {a1}
c,继续选择下一个活动,该活动满足两个条件:与先前已选择的活动兼容;是未选择的活动中结束时间最早的活动
d,重复上一步直到没有活动可以选择,此时得到的A为最大兼容活动集合
2,证明此贪心策略的正确性
a,S(i,j)表示成与活动a(i)、a(j)兼容的活动,求S(0,n+1)的最大兼容活动集合,即为求原实际问题的解。
b,《算法导论》中定理16.1 (1)证明了活动a(m)是S(i,j)的某个最大兼容活动集合的一个元素,而元素 a(m) 正是根据上述贪心策略选择出来的。这说明,按照上述贪心策略的选择,可以选出最大兼容活动集合中的元素。
c,再由定理16.1(2),当选择了a(m)后,求解S(i,j)的最大兼容活动集合变成求解S(m,j)的最大兼容活动集合,它将问题空间缩小了。而根据 b,求S(m,j)的最大兼容活动集合就是从S(m,j)中选择最早结束的活动!
d,因此,由 b , c 可知:根据上述贪心策略能成功地选取出S(i,j)的一个最大兼容活动集合。
--------------------------------------------------------------------------
《算法导论》介绍了很多算法分析的方法:从某个现实生活中的问题入手,然后将之一步步地转化成数学问题,再运用一些分析技术(动态规划、贪心、随机化、概率分析、分治……)将之表示成伪代码,最后就可以用编程语言将这些伪代码实现!