贪心算法
引言
和动态规划算法的相似,通常用来求解最优化问题,即量的最大化或最小化。
通常包含一个用于寻找局部最优解的迭代过程。它的每一步均是建立在局部最优解的基础上,而又扩大了部分解的规模,做出的选择产生最大的直接受益而又保持可行性
-
背包问题
可以采用贪心策略方便的解出:对于每项计算vi / si ,即该项的价值与体积之比,再按照比值的降序排列,从第一项开始装包,直至装不下。
在维持可行性的前提下,它选择能产生最大直接利益的项。
最短路径
输入:含权有向图G=(V,E),V={ 1,2,…,n }
输出:G中顶点1到其他顶点的距离
设G=(V,E)是一个每条边有非负长度的有向图,有一个特异顶点S为源点
单源最短路径(简称为最短路径问题 )就是要确定S到V中每一个其他顶点的距离
初识时将顶点分为两个集合X={ 1 },Y={ 2,3,…,n },X中的顶点是源点到这些顶点的距离已经确定的。在每一步中,我们选择Y中已经获得与源点距离的顶点y,并加入X中。然后更新与y相邻的每个顶点w的标记,表示找到了经过y到w的更短路径。
ℒ[y]表示只经过X中顶点的最短路径的长度
算法DIJKSTRA1
X = {1}; Y=V-{1}; ℒ[1]=0
for y: 2 to n
if y邻接于1 then ℒ[y]=length[1,y]
else ℒ[y]=∞
end if
end for
for j: 1 to n-1
令y∈ Y,使得ℒ[y]为最小
X= X U {y}
Y= Y - {y}
for 每条边(y,w)
if w∈ Y and ℒ[y]+length[y,w] < ℒ[w] then
ℒ[w]= ℒ[y]+length[y,w]
end for
end for
假设输入由邻接表表示,边(x,y)的长度存放在x的邻接表的y顶点中,把两个集合X和Y用布尔向量X[1…n]和Y [1…n]来表示:初始时X[1]=1,Y[1]=0,并且对于所有的其他顶点都设置为X[i]=0,Y[i]=1。该点进入X通过置X[i]=1,Y[i]=0来实现。
最小耗费生成树(Kruskal)
输入:包含n个顶点的含权无向连通图G=(V,E)
输出:由G生成的最小耗费生成树T所组成的边集
简记为避圈加边法
最小生成树:(V , T)是G的一颗生成树,如果给G加权并且T各边的权重的和为最小值。
算法概括为
- 对G的边以非降序的权重排列
- 对于排序表中的每条边,如果加入T不会形成环路,则把它加入生成树T中,否则将它丢弃
算法KRUSKAL2
按非降序的权重将E中的边排序
for 每条边v∈ V
MAKESET( {v})
end for
T ={}
while |T|<n-1
令(x,y)为E中的下一条边
if FIND(x) != FIND(y) then
将(x,y)加入T
UNION(x,y)
end if
end while
最小耗费生成树(Prim)
输入:包含n个顶点的含权无向连通图G=(V,E)
输出:由G生成的最小耗费生成树T所组成的边集
N[y]是X中具有以下性质的的那个点:在所有X的邻接于y的顶点中,c[x,y]最小。也就是说N[y]是X 中离y最近的邻居。我们定义c[y]=c[y,N[y]],它是连接y和N[y]边的耗费。
算法PRIM3
T = {}; X = {1}; Y = V-{1}
for y: 2 to n
if y邻接于1 then
N[y]=1
C[y]=c[1,y]
else C[y]=∞
end if
end for
for j: 1 to n-1 {寻找n-1条边}
令y∈ Y,使得C[y]最小
T = T U {(y,N[y])} {将边(y,N[y]加入到T)}
X = X U {y}
Y = Y - {y}
for每个邻接于y的顶点w∈ Y
if c[w,y]<C[w] then
N[w]=y
C[w]=c[y,w]
end if
end for
end for
在每次迭代中,具有最小C[y]的顶点被移动到X中之后,Y中每个与y相邻的顶点w都需要更新N[w]和C[w]
文件压缩
输入:n个字符的集合C={ c1,c2,…,cn }和它们的频度{ f(c1), f(c2),…, f(cn) }
输出:C的Huffman树(V,T)
展示的算法由Huffman提出。由该算法构造的编码满足前缀约束,并且最小化压缩文件的大小
前缀约束:一些字符的编码不能是另一个字符编码的前缀,可以防止编码的二义性
直观上来说,频度大的字符将被赋予短的编码,而长的编码可以赋给那些频度小的字符
算法HUFFMAN4
根据频度将所有字符插入最小堆H
V = C ; T ={}
for j: 1 to n-1
c= DELETEMIN(H)
c''= DELETEMIN(H)
f(v) = f(c)+f(c'') { v是一个新的节点 }
INSERT(H,v)
V = V U {v}
T = T U {(v,c),(v,c'')} { 使c和c''称为T中v的子节点 }
end while