贪心算法的基本概念
"首先需要强调的是,01背包问题的前提是每件物品都只有两种状态:被选和没有被选.并不能将一件物品的一部分装入背包.这正是01背包中01的意义.如果可以将一件物品的一部分装入背包,那么完全可以采用比动态规划更简单的思路:通过每件物品的价值/重量求出每件物品的价值密度(我自己编的名词).然后从高到低取物品即可.这种思路就是一种简单的贪心算法思路.因为01背包题目中的物品只能取或者不取,所以在其容量与物品重量有较大冲突时,用简单的贪心算法并不能得到正确的结果."
上一章在介绍01背包问题时就简单地提到了贪心算法.在普通的背包问题中,向容量有限的背包中装入多种物品,每件物品存在重量与价值两个属性,并允许被拆分,要求计算背包可以容纳的最大价值.用贪心的思路去想,显然我们要优先装入单位重量价值更大的物品.根据这个思路,就可以轻松地解决背包问题了.
贪心算法可以理解为在每一个局部选择局部的最优解,并得到一个整体的最优解.当然,在很多情况下,贪心算法得到的结果并不是真正的最优解,因为题目考察的可能是动态规划这种更具有考察价值的算法.但是,动态规划得到的结果往往会比较接近最优解.所以贪心算法在算法题中,可以作为动态规划题目找不到状态转移方程时的骗分手段,有那么多测试点,总得有贪心算法恰好是最优解的情况吧.
当然,不去谈这些邪门歪道,贪心算法也是具有很深远的意义的,它更多的是一种解决问题的思路.例如面对单源最短路径问题的重要算法Dijkstra算法,以及面对最小生成树问题的Prim算法与Kruskal算法,都采用了贪心的思路.今天我们试着理解贪心算法,也主要通过上述的三个算法来进行.需要声明的是,由于笔者精力和能力的限制,上面的算法我的描述也许会相对抽象,不会有太多生动的模拟过程,读者如果感到理解吃力,我会附上推荐的学习链接地址.
Dijikstra算法解决单源最短路问题
单源最短路问题描述:
在一个图中,求某个点到其它所有点的最短路径的长度.
在此我们采用下面的图例来模拟算法过程.如下图所示是一个图,图中包括多条边,每条边有不同的权值,所谓最短路径就是从一个点走到另一个点走过的边的权值之和最小.我们需要求出结点1到其它所有点的最短路长度.
对于这张图,我们可以采用邻接矩阵的方式储存,在此我们设为Graph[][],其中Graph[i][j]代表结点i到结点j的边的权值.对两个并不直接相连的结点,它们之间的边权值被认为是无穷大.下面的表是对本案例我们初始的Graph[][]邻接矩阵.
1 | 2 | 3 | 4 | 5 | 6 | |
1 | 0 | 1 | 2 | MAX_INT | MAX_INT | MAX_INT |
2 | MAX_INT | 0 | 9 | 3 | MAX_INT | MAX_INT |
3 | MAX_INT | MAX_INT | 0 | MAX_INT | 5 | MAX_INT |
4 | MAX_INT | MAX_INT | 4 | 0 | 13 | 15 |
5 | MAX_INT | MAX_INT | MAX_INT | MAX_INT | 0 | 4 |
6 | MAX_INT | MAX_INT | MAX_INT | MAX_INT | MAX_INT | 0 |
除此之外,我们需要一个一维数组optimum[],其中optimum[p]代表结点1到结点p的最短路径长度.初始状态下,只有与结点1直接相连的结点存在一个当前的最短路,随着我们的计算,optimum[]数组被逐渐填满,当每个节点都被标记为确定时,optimum[]数组的数值就会确定,成为我们的最终答案.下图就是面对本案例我们初始的optimum[]数组情况.
1 | 2 | 3 | 4 | 5 | 6 |
0 | 1 | 12 | MAX_INT | MAX_INT |
MAX_INT |
之所以认为贪心思路被应用到了Dijikstra算法中,是因为Dijikstra算法在每一步中,假如这一步中的optimal[x]为最短路径,那么我们就认为初始结点1到结点x的路径已经确定,这种取局部最优解的思路正是一种贪心思路.
Dijikstra算法的过程模拟
下面我们来模拟Dijikstra算法的过程:
第一步:
对于初始状态的optimun数组:
1 | 2 | 3 | 4 | 5 | 6 |
0 | 1 | 12 | MAX_INT | MAX_INT |
MAX_INT |
除了1结点自身对自身的距离为0,,我们发现当前的最短路径是1->2的路径,距离为1,那么我们认为1->2的最短路径已经确定就是1,我们将结点2加入已经确定的图中.
我们可以理解为当前只考虑了下面的局部图,其中绿色的节点代表最短路已经确定的集合:
第二步:
既然节点2已经确定,不妨将节点2的直接相邻节点也加入optimum[]数组,如果1->2已经是最短的了,那么1->2的临点也会有可能最短的通路.首先,2->3,且Graph[2][3]+optimum[2]=1+9=10<optimu