优化问题的算法通常会通过一系列的步骤,在每一个步骤通过一系列的选择。一个贪婪算法总是目前看起来最好的选择。也就是说,它做出局部最优选择,希望选择将导致全局最优的解决方案。贪心算法并不总是能得到最优解,但对于许多问题它们都能得到最优解。
活动选择问题
几个相互竞争的活动需要共同的资源,目标是在活动不发生冲突的前提下,选出最多可举办的活动数。假设我们有一个集合提议希望使用资源的活动,例如一次只能由一个活动使用的演讲厅。每个活动ai都有一个开始时间si和一个结束时间fi, 。如果选择,活动ai发生在半开时间间隔[si,fi)的情况下,活动ai和aj是兼容的,间隔[si,fi)和[sj.fj]不重叠的。活动选择问题是选择相互兼容的活动的最大子集。
按开始时间最早的排序;X
按时间间隔最短的排序;X
按结束时间最早的排序;√
最小生成树问题(Minimum spanning trees,MST)
在电子电路的设计中,把几个零件的引脚连接在一起就通电了。互连一组n个引脚,我们可以使用一个n-1线的排列,每根连接2个引脚。在所有这些安排中,使用的那个最少的电线通常是最多的引脚。我们可以用一个连通的无向图G=(V,E)来建模这个布线问题,其中V是引脚的集合,E是引脚对之间可能的相互连接的集合,对于E中的每条边(u,v),我们都有一个权值w(u,v)来指定连接u和v的代价(所需的导线数量),需要找到无圈的子集把所有的引脚连接起来,并使得权值最小。因为T是非圈的,并且连接所有的顶点,所以它必须形成一棵树,我们称之为G的生成树,T就是最小生成树。
假设有一个连通的无向的图G=(V,E),及权值函数。我们希望找到G的最小生成树。我们在这里考虑的两个算法使用贪婪的方法解决问题。
这个贪心策略由下面的“一般型”算法延伸,该算法每次只增长最小生成树的一条边。该算法管理边集A,A不断加1条边,需要做n-1次循环。在每次迭代之前,A是最小生成树的子集。在每一步,我们确定可以添加到A的边{u,v},在不违背这个不变式的情况下,还是最小生成树的一个子集。我们称这样的边为A的安全边,因为它可以在保持不变的情况下添加到A。
1
2
3
4
5
6 GENERIC-MST(G,w)
A ← ?
while A does not form a spanning tree
do find an edge e that is safe for A
A ← A ∪ e
return A如何找到安全的边?
我们首先需要一些定义。无向图G=(V,E)的一个cut(S,V-S)是V的一个分划。如果它的一个端点在S中,另一个端点在V-S中,我们说一条在E中的边(u, v)穿过这个cut(S,V-S)。如果A中的边没有与该cut相交,则该cut respects A组边。如果边的权值是任何边穿过cut的最小值,则边就是穿过cut的轻边。注意,还可以有更多轻边,那么选择其中一条即可。简单来说,就是A+安全边就是最小生成树的子集,A中的点没有穿过cut,再在cut中找到轻边作为安全边,得到新的A,然后再找到新的cut,满足A没有穿过cut,循环此过程,直至找到n-1条边。
定理:设G=(V,E)是连通的具有权重w的无向图,令A是E的子集,包含在G的最小生成树中。设(S, V-S)为任意cut(respect A),设(u,v)为穿过(S, V-S)的轻边。那么(u,v)是A的安全边。
证明:设T是一个最小生成树,包含A,并假设T不包含轻边(u,v)。如果是这样,我们就完成了。我们将构造另一棵最小生成树T',通过使用cut-and包括U {U,v}粘贴技术,从而显示(u,v)是aA的安全边。
边(u,v)与在T中路径p从u到v的边形成一个循环,因为u和v是cut(S, v -S)的相对边,所以在路径p中至少有一条边也穿过cut。设(x,y)是任意一条这样的边。这条边(x,y)不在A中,因为cut respect A。因为(x,y)在T中从u到v的唯一路径上,所以删除(x,y)把T分成两个部分。添加(u, v),从新的生成树重新连接它们接下来证明T'是最小生成树。因为(u,v)是一个轻的边缘交叉(S, v -S)和(x,y)也穿过这条线,w(u,v)<=w(x,y)因此,w (T ') = w (T) - w (x, y) + w (u, v) < = w (T)。但是T是最小生成树,所以T'也必须是最小生成树。
对于当前生成树T,u,v之间没有直接的边相连,但可以通过路径p连通,按图中将G分割为cut两部分,使得u, v在cut不同的点集,那么必然存在这样 的x,y也被划分在cut两部分,边(u,v)(x,y)都穿过该cut,(u,v)是轻边,连接(u,v),断开(x,y),得到新的生成树T‘,而且(u,v)是轻边,那么T(w)≥T'(w)。
Kruskal , Prim它们使用特定的规则来确定安全边界。
克鲁斯卡尔算法(Kruskal)和Prim算法
集合A是一个森林。添加到A的安全边总是图中连接两个不同组件的最小权重边(即选择图G中未连接的权值最小的边)。在Prim的算法中,集合A形成一个单一的树。添加到A的安全边总是最小权值将树连接到不在树中的顶点的边(从当前解的生成树往外连接权值最小的边)。
Prim算法: 假设从a出发,先走ab,bc和ah的权值一样,任选一条,这里走bc,w(ci)
为了验证正确性,可以从任意点出发,再次选择一遍,结果是一样的,假设从d出发,下图是按d出发的cut选择。
Kruskal算法:按照权值从小到大连接,最小的是w(hg)=1,那么选择过程:hg,gf,ci,cf,ab,cd,cb,de。下图显示前五步选择。
最大独立集(Maximum independent set)
我们要找到最大的独立集合。如果我们用贪心算法解决问题,假设顶点的度越小越好。事实上,每当我们加上一个点到目前的解,我们也要把它的所有邻居都清除掉。因此,首先选择度较小的顶点可能会使我们获得一个最大的独立集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Greedy independent set input Graph G=(V,E); output independent set V' in G; begin V':=ф U:=V while U is not empty do begin x: vertex of minimum degree in graph induced by U V':=V'U(x); eliminate x and all its neighbors from U end return V' end |
贪心算法找不到最大独立集的例子:
a是最小度的点,a放入解集,删除邻居b,c,d,剩下e,f,g任选一个点,那么最大独立集为两个点。但最大独立集是三个点{b,c,d}。
可以看出,存在一个顶点数不断增加的图序列,对于这个图序列,该算法所得到的解的度量值与最优值相差甚远。
可以使用图的密度函数判断贪心算法的表现。
定理:假设图G有n个点和m条边,记为图G的密度。贪心算法求得的解
证明:
证明:设xi为程序while循环第i次迭代时选定的顶点,di(删除邻居后子图的度)为xi的度。然后,该算法将xi及其所有di邻居从G中删除。第i步删除di+1个点,得到第一个式子,又因为删除点的同时会删除边,那么与xi相连的di个点至少度是di,那么删除的边有(di+1)di,di个点之间可能存在互相连接的情况,那么删除的边至少有(di+1)di/2,删除的边数一定小于总边数,得到第二个式子,(2)*2+(1)得到。利用柯西斯瓦格不等式,对于所有的i,当时,不等式的左边取得极小值。,定理得证。
下面的定理提供了最优解与贪婪算法求得的解之间的关系。
定理:有n个顶点和m的图G,设。程序找到一个独立的集合,令最优解。
证明:本证明与前一证明相似。在本例中,我们在在(2)中另外计算与某个最优解的顶点相关联的边的数目。即,确定一个最大的独立集合V*,令ki为在第i次循环中所删除di+1个顶点并在V*中的顶点数。明显地,,由于贪心算法选择的顶点最小度,删除的顶点的度的和至少是di(di+1)。因为一条边的两个端点不可能都在V*中,它这样删除边的数目至少为(di(di+1)+ki(ki-1))/2,这里可以提高(2),得到,(2)+(3)+2*(4)得到。应用CS不等式,当,上述不等式左边最小,因此,,即,当m*(G)=n时,不等式最小。通过把这一项代入,定理就成立了。
背包问题(Greedy knapsack)
输入:集合X的n个元素,对于X中的每个xi,价值pi,重量wi,正整数b;
输出:子集使得
按pi/wi的规则进行贪心选择。
1 2 3 4 5 6 7 8 9 10 11 | begin sort X in non-increasing order with respect to the ratio pi/wi; Y:=empty set; for i=1 to n do if b>=wi then begin Y=YU{xi} b=b-wi end return Y end |
反例:
例:令pi=wi=1,i=1,2,..,n-1, pn=b-1, wn=b=kn,其中k是一个任意大的数。在这种情况下,最优解m*(x)=b-1;而贪心算法找到的解的值为n-1。因此m * (x) /mGr(x) > k。
发现贪心算法的劣势是由于算法没有将价值最高的元素包含在解中,而最优的元素正是价值最高的。这表明一个简单的修改贪心的程序有更好的性能。
定理:给定一个背包的实例x,令mH(x)=max(Pmax,mGr(x)),其中Pmax是x中一个项目的最大价值,mH(x)满足以下不等式:。
证明:设j为根据贪心选择第一个装不进背包物品的下标,此时背包转装入的物品价值为,重量为。我们首先证明任何最优解必须满足以下条件不等式:,(因为装入前j-1个物品后,容量还剩余,贪心选择在装入j-1个物品后,无法装入j,其密度为pj/wj,那么如果剩余容量按最优的去放,)。如果,那么;如果,那么,有
The Stein-lovasz Theorem(ST)
定理:设A是一个N行M列(0,1)矩阵。假设每一行至少包含v个1,每一列至多包含a个1。然后存在一个NXK子矩阵C(没有全0行,每一行至少有一个1的矩阵)满足:。可以想象为关联矩阵,每一列用超边连接,如何用最少的超边把所有的行覆盖掉,每条超边覆盖的点满足,利用贪心策略,每一步的超边尽可能选最多的行。
举例:
点集X={1,2,3,4,5,6},超边集合={{1,3,4},{2,4,5},{1,5},{3,5},{5,6},{4},{6}},从超边集合选择最少的子集合,覆盖所有的行,那么选择{1,3,4},{2,4,5},{6}最少的超边子集合。
证明:
假设,表示由a个1且每列的1互不重合的列组成的矩阵,,那么删除覆盖的行得到新的矩阵,那么每一列至多有a-1个1,表示由a-1个1且每列的1互不重合的列组成的矩阵,,那么删除覆盖的行得到新的矩阵,以此类推。,每行至少v个1,每列至多i-1个1,那么有行,令其记为,有列。,即,令,则,以此类推得到,。使用双计数,分别对行和列进行计数,对于,每一行至少v个1,而每列至多i-1个1,可得对1进行行计数不会超过进行列计数,即,,那么。
应用:
1. 完美哈希族
(n,m,w)-完美哈希族是一个函数F集合,使得|Y|=n, |X|=m, 对于F中的每一个f,对于任何使得,C是Y的w元子集合,并且至少存在一个F中的f使得f|C是一一对应的。如果|F|=N那么完美哈希族可以记作PHF(N;n,m,w)。
|F|=N,如上图,假设w=3,那么任选Y中的三列,有种选择,要求其中存在一行使得三个函数值各不同,例如取1,2,3列,f11,f12,f13互不相同就满足要求一一映射。
,n个Y对应到m个X,每一个Y有m种选择,那么有个函数。从中挑出最少的函数(即上图的N越小越好)使得对于任何的C可以满足一一对应要求。
套用ST定理,找到对应的N,M,v,a,套用公式,就可以得到函数数目的一个上界。
需要完成的事情,从个函数中挑选出最少的函数满足要求,那么得到的矩阵就是NxM的(0,1)矩阵A,Aij=1的含义就是当|w|=i,fj是可以满足一一映射要求的。,表示从m个值中选取w的值排列放入选择的w个,剩余未赋值的n-w个,就任意赋值。,每一个函数至多覆盖a个。套用ST定理得。
使用概率方法,从个函数中随机选择N个函数出来,构造一张随机的函数表,考虑坏概率,在函数表中没有一个函数可以使w存在一一映射关系,对于一个函数坏概率为存在一一对应关系的对立事件,取出N个函数,得,使其小于1,那么一定存在完美哈希族。(两边取对数求解)
2.分割系统(Splitting Systems)
在某个域中,,已知且为离散的,那么如何求解n?分割系统的提出就是为了解决离散对数问题。
假设n,t为偶数,0
)(X是点集合,是超边集合): a) |X|=n, 是X的n/2子集的集合,称为区组
b)对于每一个使得IY|=t,在中存在区组B,使得。
最少N的B使得上面的条件满足。
使用ST定理,,对所有的t元子集合进行分割,,完成的方法总数,接下来确定v,那么对于某一行有多少n/2元子集合可以分割ti,t个位置中一半放1,剩余一半放0,问题是一个n元集合,此时还剩n-t个位置没有放数,且还缺少(n-t)/2个1,那么得到子集合个数;确定a,对于固定的n/2元子集合可以分割多少t,,套用ST定理,
使用概率方法:
定义Ai,第i个t元子集合未被分割。对于一个t元集合没有分割的概率是分割时间的对立事件,为,共有N个n/2元子集合未被分割,为,那么至少有一个t元集合未被分割的概率为,令其小于1,那么没有未被分割的情况概率大于0。