【图论学习笔记四】启发式算法

在启发式算法的上下文中,启发式将是执行小的修改的一种方法,或一系列的修改,对给定解或部分解的修正,为了得到不同的解或部分解决方案。实际的修改这些工作将涉及到邻居搜索。按照一定的设计策略,一个启发式算法将包括迭代地应用一个或多个启发式。

1,柯克曼女生散步问题(Kirkman Schoolgirl)

柯克曼女生散步问题是世界上最难的一百道数学题之一,许多人对它充满兴趣,有些数学爱好者甚至花费几年时间来钻研它。这道题题意是这样的:“15个女生每天分组散步1次, 3人1组,规定1个星期内任意2人都有1次(且仅1次)编在同组。要求排出1个星期的分组方案。

这个问题的充分必要条件是,人数满足6k+3就可以分出满足要求的方案。

 启发式算法过程:假设一个初始解,这个解可以不满足要求,例如7天的分组都是一样的,对于每一个出现的点对T(i,j),当\sum (T-1)降到0时,就找到了解,降得过程就是随机交换分组中的元素,使得求和在不断下降,直到0。例如可以使用禁忌交换,每一天选择最优的,即下降最快的进行交换。

2,组合优化问题(Combinatorial optimization problem)

为了使这些概念更加精确,我们考虑一个通用的组合优化问题。解是从一个特殊的有限集合X中选择的,集合X,我们称之为universe(可理解为解空间)。一个元素x∈X,是一个可行解,当某些约束条件得到了满足。约束可以写成g_j(x)\geq 0,1\leq j\leq m,其中g1,g2…gm是整数值函数。最优解是一个可行解x,其中利润P(x)尽可能大。

通用的优化:

实例:一个有限的集合X;

        目标函数P:X→Z;

        可行函数g_j:X\rightarrow Z,1\leq j\leq m

求P(X)的最大值取决于x\in X\ and\ g_j\geq 0,1\leq j\leq m

 构建启发式的第一步是定义一个邻域函数N: X\rightarrow 2^X。用通俗的话说,任何X中的元素的邻居由X的元素的子集组成。我们一般会定义a元素x的邻域由特定的元素组成“相似”或“接近”x,在某种意义上。注意邻域N(x)可能包含不可行的元素。

让我们举几个典型邻域函数的例子。首先,假设X=\{0,1\}^n。然后我们可以定义N_d(x)=\{y\in X:dist(x,y)\leq d\}

(元素改变的数目为Hamming Distance),其中d是某个正整数,dist(…)表示两个n元组的汉明距离。观察在这种情况下,我们可以很容易地计算出邻域的大小为|N_d(x)|=\sum_{i=0}^{d}\binom{n}{i}

第二个例子,假设X由集合{1,...,n}的所有排列组成,给出两个排列\alpha =[\alpha 1,...,\alpha n],\beta =[\beta 1,...,\beta n],假设我们定义\alpha\beta之间的距离dist(\alpha ,\beta )=|{i:\alpha i\neq \beta i}|。我们可以定义N_d(x)=\{y\in X:dist(x,y)\leq d\}(错排问题,例如拿错帽子问题)。

一旦邻域函数被定义,我们我们能想象出不同的方式试着找出一个可行的解,对给定可行解x的邻域。一个明显的方法是执行对附近进行彻底的搜索(穷举),试图找到“最佳”可行的解决方案在这附近。然而,许多启发式算法是基于随机邻域搜索,通常比穷举更快。更正式地说,假设N是邻域函数。基于N的邻域搜索是一种算法,输入是一个可行解x\in X,输出也是一个可行解y\in N(x)/\{x\},或者无效解。因为N(x)可以包含不可行的元素,邻域搜索必须保证元素y的输出是确实可行的。这可以通过检查可行性功能。

邻域搜索策略:1. 找到一个可行解y使得P(y)是最大化。2. 找到一个可行解y使P(y)最大化。如果P(y)>P(x),则返回y,否则返回失败。3.求出N(x)的任意可行解。4. 求出N(x)的任意可行解。如果P(y)>P(x),则返回y,否则返回失败。

现在,指定了一个邻域搜索策略,基于给定邻域函数N,我们可以继续定义启发式hN。最常见的定义hN去做邻域搜索。然而,它可能在某些情况下需要做一系列的邻域搜索。最后,启发式将是合并到启发式算法中。

Generic Heuristic Search
external N(),hN(),P()
c←0
select a feasible solution x in X
x(best)←x
while c<=cmax
    do y ← hN(x)
        if y ≠ Fail
            x ← y
            if P(x)>P(x(best))
                x(best)←x
        c←c+1
return(X(best))

均匀分区图(均匀把图的点分开,并使得交叉的边最少)

实例:一个完全图有2n个点;一个代价函数,E\rightarrow Z^+\cup \{0\}

查找:c([X_0,X_1])=\sum_{{u,v\in E,u\in X0,v\in X1}}cost(u,v)的最小值,根据V=X_0\cup X_1,|X_0|=|X_1|=n

我们可以把解空间X设定为V的所有分区[X0,X1]和|X0|=| X1|的集合。将分区[X0,X1]的邻域定义为可以从[X0,X1]获得的所有分区的集合,通过交换X0的一个顶点和X1的一个顶点。从交换u \in X0,v \in X1得到的收益(成本的变化)是G_{[X0,X1]}(u,v)=C(X0,X1)-C(X0/\{u\}\cup \{v\},X1/\{v\}\cup \{u\}) = \sum_{y \in X1}cost(u,y)+\sum_{x \in X0}cost(x,v)-\sum_{y \in X1}cost(v,y)-\sum_{x \in X0}cost(x,u)

给定一个分区[X0,X1],一个简单的邻域搜索就是找到分区[Y0,Y1],其中Y0=(X0/\{u\}\cup \{v\}),Y1=(X1/\{v\}\cup \{u\}),u \in X0,v \in X1,使u与v交换的增益最大。如果这是不可能的,返回失败。

3.启发式算法设计策略(Design Strategies for Heuristic Alg)

任何启发式算法必须考虑的权衡。如果我们用"大"的邻域,那么我们可以期待任何一个邻域更有可能包含好的解,比使用“小”的邻域。特别是在穷尽的情况邻域搜索,如果邻域很大,我们付出计算时间代价。

爬山法(Hill-Climbing)

概念上最简单的设计策略是爬山法。我们要求P(y)>P(x)对于任意y返回邻域搜索的输出。如果附近没有找到这样的人y,返回失败。因此,我们试图通过寻找一系列可行解来得到一个最优解,每个可行解都比前一个更好。爬山的比喻是不断向上攀登(当然,这在实践中可能不是真的!)如果邻域搜索策略是穷举的,那么我们使用的是我们之前描述过的最陡峭的上升点。

爬山策略往往过于局限而不能成功。如果)对于N(x)中的所有可行解y,P(y)<P(x),然后用爬山算法求解这样的一个x称为局部最优解,在一个典型的组合优化问题中,可能有很多局部最优解。

模拟退火法(Simulated annealing)

一种规避局部最优解的方法是基于一种被称为“退火”的金属冷却方法的类比。因此,相应的算法范例被称为模拟退火。在模拟退火中,我们使用随机邻域搜索策略。如果hN(x)=y是可行的,并且P(y)≥P(x)则x被y代替,就像爬山一样。但是如果hN(x)=y可行,P(y)<P(x),那么我们有时可以用y来代替x,这样的向下移动是有一定概率的。这使得算法能够逃离局部最优解。与模拟退火算法相关的是一个称为温度的变量T。将T初始化为T0>0的值。在算法的过程是根据给定的冷却时间表来描述T的值。在算法的任意点,给定P(x)>P(y)条件下,用y=hN(x)替换x的概率是e^{(P(y)-P(x))/T}。这是通过生成一个随机数r \in [0,1],并用y替换可行解x,如果r<e^{(P(y)-P(x))/T}。它仍然需要指定一个冷却时间表。通常,T在每次迭代后,根据T\leftarrow \alpha T公式,其中0<\alpha <1是某个常数(通常\alpha接近1,如\alpha=0.99)。一开始,允许的概率下行幅度将相对较大。然而,当T减小时,这个概率也减小。因此,当我们越接近最优解,向下移动的概率就越小。

禁忌搜索(Tabu Search)

禁忌搜索可以被认为是最陡峭上升的一种变化。基本思想是将元素x替换为元素y \in N(x)/\{x\},这样y是可行的,并且P(y)在所有可行元素中是最大的。这通常包括对N(x)的彻底搜索。P(y)<P(x)可能发生。因此,我们可以用这种方法逃离局部最优解x。但是,y代替了x,在这种情况下,下一步很可能是用x替换y。这显然是不可取的,因为将进入一个无限循环,它无法从中逃脱。因此,我们需要找到一种方法以避免这种情况和其他类似的问题,如骑自行车(如x→y→z→x)的一系列动作。这是通过一个禁忌表来完成的。

假设我们定义一个函数change(x,y),它指定了对一个可行解x所做的更改,以获得一个可行解y。在算法的某一点做了一个给定的改变,我们不希望执行任何将“撤消”此更改的操作(至少在经过一段时间之后)。因此,在移动x→y之后,change(y,x)被指定为禁止更改,并被添加到禁忌表中。在指定的生命周期内,禁忌表上的更改仍然是禁止的。参数L是一个固定的正整数。作为一个例子,假设X=\{0,1\}^n,N(x)=\{y\in X:dist(x,y)=1\},x的邻域由所有的二维n元组组成,其中x的一个元素被改变了。因此|N(x)/x|=n。假设我们定义change(x,y)=i 当且仅当 x_i\neq y_i。因此,如果可行解的第i项改变(从0到1或从1到0),至少经过算法的L次迭代,都不能再改变回来。我们还有另一个权衡L的例子,在设计算法时需要考虑。我们希望L要“大”,以消除循环,但如果L变得太大,那么在算法中的任何给定点都不会有很多允许的移动。这可能会使找到好的解决方案变得困难。

揹包问题(knapsack problem)

n个物品,价值为P0,...,Pn-1,重量为W0,...Wn-1,揹包容量为M。解空间为X=\{0,1\}^n,一个X中的n元组x=[x0,...,x(n-1)]是可行解,如果w(x)=\sum_{i=0}^{n-1}x_iw_i\leq M,最大化目标P(x)=\sum_{i=0}^{n-1}x_ip_i

模拟退火法:假设我们把邻域函数定义为N_1(x)=\{y \in \{0,1\}^n:dist(x,y)=1\},我们可以生成一个随机的y=[y_0,...,y_{n-1}]\in N(x),随机选择一个整数j,使0<=j<=n-1,然后定义y_i=x_i\ if\ i\neq j;1-x_i\ if\ i=j。显然w(y)=w(x)+w_j\ or\ w(x)-w_j。一个类似的公式把P(y)和P(x)联系起来。假设x是可行的。那么y是可行解,无论当xj=1,或xj=0且w(x)+wj<=M时,都是可行的。如果xj=0且w(x)+wj>M,则启发式hN失败。现在假设y=hN(x)是可行的。如果xj=0,那么P(y)>P(x),在模拟退火算法中,x总是被y所代替。如果xj=1,P(y)<P(x),在这种情况下,P(y)-P(x)=-Pj;因此,x将以概率e^{-Pj/T}被y所代替。最后,从初始可行解[0…,0]开始。给定一个问题实例,仍然需要确定T0、Cmax和\alpha的合适值。这基本上是一个实验问题。

禁忌搜索法:使用与模拟退火法相同的邻域。因此,更改包括选择索引i,并用1-xi替换xi。i的这些值将存储在禁忌表中。禁忌搜索算法将对邻域进行穷举搜索,以找到更新可行解x的“最佳”方法,而不是模拟退火中的随机搜索策略。最好查看迭代的利润/权重比值,而不仅仅是它们的利润。因此,邻域搜索策略可以描述为:1. 假设至少存在一个索引i,其中xi=0,使得i不在当前的列表中,并且xi可以在不超过容量M的情况下被更改为1。在所有的i中,选择Pi/wi最大的一个,把xi从0变成1。2. 假设没有i满足上面的条件。然后考虑所有i,使得xi=1并且i现在不在列表上。在这些i的值,选择Pi/wi这样的值最大值,把xi从1变成0。

上面描述的启发式是确定性的。一个将随机性引入算法的简便方法是从一个随机可行解开始。

还要做两个其他的决定。一个是L的生命周期。当然,用不同的L值运行算法并确定最佳选择是一件很简单的事情。另一个问题是我们应该进行多少次迭代允许算法运行。许多禁忌搜索结果是对执行次数相当不敏感。在搜索的早期,最好的可行方案往往是非常容易找到的。因此,我们可以取Cmax为相当小(比模拟退火的要小得多)。

局部化策略

有不少数学问题描述的是整体的特征,整体的结果,但是,,由于所给条件的任意性,变量多,我们不容易从整体进行分析,这时我们可以暂时放下整体而去考虑局部,或者集中力量先解决某一局部问题,或者对局部进行逐步调整,再回到整体上去。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章