经典贪心算法(哈夫曼算法,Dijstra单源最短路径算法,最小费用最大流)
哈夫曼编码与哈夫曼算法
哈弗曼编码的目的是,如何用更短的bit来编码数据。
通过变长编码压缩编码长度。我们知道普通的编码都是定长的,比如常用的ASCII编码,每个字符都是8个bit。但在很多情况下,数据文件中的字符出现的概率是不均匀的,比如在一篇英语文章中,字母“E”出现的频率最高,“Z”最低,这时我们可以使用不定长的bit编码,频率高的字母用比较短的编码表示,频率低的字母用长的编码表示。
但这就要求编码要符合“前缀编码”的要求,即较短的编码不能是任何较长的编码的前缀,这样解析的时候才不会混淆。要生成这种编码,最方便的就是用二叉树,把要编码的字符放在二叉树的叶子上,所有的左节点是0,右节点是1,从根浏览到叶子上,因为字符只能出现在树叶上,任何一个字符的路径都不会是另一字符路径的前缀路径,符合前缀原则编码就可以得到。
现在我们可以开始考虑压缩的问题,如果有一篇只包含这五个字符的文章,而这几个字符的出现的次数如下:
A:
6次
B
: 15次
C:
2次
D
: 9次
E:
1次
用过用定长的编码,每个字符3bit,这篇文章总长度为:3*6
+ 3*15 + 3*2 + 3*9 + 3*1 = 99
而用上面用二叉树生成的编码,总长度为:
2*6 + 3*15 + 2*2 + 2*9 + 2*1 = 80
字符 |
编码 |
A |
00 |
B |
010 |
C |
011 |
D |
10 |
E |
11 |
显然,这颗树还可以进一步优化,使得编码更短,比如下面的编码
生成的数据长度为:3*6
+ 1*15 + 4*2 + 2*9 + 4*1 = 63
下面我们先来介绍哈弗曼算法是如何构造最优二叉树的。
哈夫曼算法的步骤是这样的:
- 从各个节点中找出最小的两个节点,给它们建一个父节点,值为这两个节点之和。
- 然后从节点序列中去除这两个节点,加入它们的父节点到序列中。
- 重复上面两个步骤,直到节点序列中只剩下唯一一个节点。这时一棵最优二叉树就已经建成了,它的根就是剩下的这个节点。
比如上面的例子,哈弗曼树建立的过程如下:
1)
列出原始的节点数据:
2)
将最小的两个节点C和E结合起来:
3)
再将新的节点和A组合起来
4)
再将D节点加入
5)
如此循环,最终得到一个最优二叉树
生成的数据文件长度为:
3*6 + 1*15 + 4*2 + 2*9 + 4*1 = 63
下面我们用逆推法来证明对于各种不同的节点序列,用哈弗曼算法建立起来的树总是一棵最优二叉树:
- 当这个过程中的节点序列只有两个节点时(比如前例中的15和18),肯定是一棵最优二叉树,一个编码为0,另一个编码为1,无法再进一步优化。
- 然后往前步进,节点序列中不断地减少一个节点,增加两个节点,在步进过程中将始终保持是一棵最优二叉树,这是因为:
- 按照哈弗曼树的建立过程,新增的两个节点是当前节点序列中最小的两个,其他的任何两个节点的父节点都大于(或等于)这两个节点的父节点,只要前一步是最优
二叉树,其他的任何两个节点的父节点就一定都处在它们的父节点的上层或同层,所以这两个节点一定处在当前二叉树的最低一层。 - 这两个新增的节点是最小的,所以无法和其他上层节点对换。符合我们前面说的最优二叉树的第一个条件。
- 只要前一步是最优二叉树,由于这两个新增的节点是最小的,即使同层有其他节点,也无法和同层其他节点重新结合,产生比它们的父节点更小的上层节点来和同层
的其他节点对换。它们的父节点小于其他节点的父节点,它们又小于其他所有节点,只要前一步符合最优二叉树的第二个条件,到这一步仍将符合。
这样一步步逆推下去,在这个过程中哈弗曼树每一步都始终保持着是一棵最优二叉树。
Dijstra单源最短路径算法
单元最短路径:给定顶点到其它任一顶点的最短路径
Dijstra单源最短路径算法的基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。
初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist作必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。
例如,对下图中的有向图,应用Dijkstra算法计算从源顶点1到其它顶点间最短路径的过程列在下表中。
Dijkstra算法的迭代过程:
迭代 |
S |
u |
dist[2] |
dist[3] |
dist[4] |
dist[5] |
初始 |
{1} |
- |
10 |
maxint |
30 |
100 |
1 |
{1,2} |
2 |
10 |
60 |
30 |
100 |
2 |
{1,2,4} |
4 |
10 |
50 |
30 |
90 |
3 |
{1,2,4,3} |
3 |
10 |
50 |
30 |
60 |
4 |
{1,2,4,3,5} |
5 |
10 |
50 |
30 |
60 |
***Floyd算法求两个顶点间的最短距离***
Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B。所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX)
+ Dis(XB) < Dis(AB)是否成立,如果成立,证明从A到X再到B的路径比A直接到B的路径短,我们便设置Dis(AB)
= Dis(AX) + Dis(XB),这样一来,当我们遍历完所有节点X,Dis(AB)中记录的便是A到B的最短路径的距离。
Floyd算法由三个for循环构成,所以时间复杂度为O(n3)
最小费用最大流
对于流f,每次选择最小费用增广链进行改进,直到不存在增广链为止。这样的得到的最大流必然是费用最小的。
增广链,指某可行流上,沿着从始点到终点的某条链上每条弧的前向弧都大于零。也称为“可改进流”
假如有这么一条路,这条路从源点(Source点)开始一直一段一段的连到了汇点(Sink点),并且,这条路上的每一段都满足流量 < 容量。那么,我们一定能找到这条路上的每一段的(容量-流量)的值当中的最小值delta。我们把这条路上每一段的流量都加上这个delta,一定可以保证这个流依然是可行流。这样我们就得到了一个更大的流,他的流量是之前的流量+delta,而这条路就叫做增广路径。
最大流最小割定理(max
flow/min cut theory):
任意一个流网络的最大流量等于该网络的最小割。
什么是割?对于一个图中的两个节点来说,如果把图中的一些边去掉(流量减为0),刚好让他们之间无法连通的话,这些被去掉的边组成的集合就叫做割了,最小割就是指所有割中权重之和最小(流量减少最小)的一个割。
最小费用最大流
若流f满足:
(a)
流量V(f)最大。
(b)
满足a的前提下,流的费用Cost(f)
=
最小。
就称f是网络流图G的最小费用最大流。
经典贪心算法(哈夫曼算法,Dijstra单源最短路径算法,最小费用最大流)的更多相关文章
- Dijkstra 单源最短路径算法
Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年 ...
- Bellman-Ford 单源最短路径算法
Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Bellman 和 Leste ...
- 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(二)
一.基于邻接表的Dijkstra算法 如前一篇文章所述,在 Dijkstra 的算法中,维护了两组,一组包含已经包含在最短路径树中的顶点列表,另一组包含尚未包含的顶点.使用邻接表表示,可以使用 BFS ...
- 单源最短路径算法:迪杰斯特拉 (Dijkstra) 算法(一)
一.算法介绍 迪杰斯特拉算法(英语:Dijkstra's algorithm)由荷兰计算机科学家艾兹赫尔·迪杰斯特拉在1956年提出.迪杰斯特拉算法使用了广度优先搜索解决赋权有向图的单源最短路径问题. ...
- Dijkstra算法详细(单源最短路径算法)
介绍 对于dijkstra算法,很多人可能感觉熟悉而又陌生,可能大部分人比较了解bfs和dfs,而对dijkstra和floyd算法可能知道大概是图论中的某个算法,但是可能不清楚其中的作用和原理,又或 ...
- 单源最短路径算法---Dijkstra
Dijkstra算法树解决有向图G=(V,E)上带权的单源最短路径问题,但是要求所有边的权值非负. 解题思路: V表示有向图的所有顶点集合,S表示那么一些顶点结合,从源点s到该集合中的顶点的最终最短路 ...
- 单源最短路径算法——Dijkstra算法(迪杰斯特拉算法)
一 综述 Dijkstra算法(迪杰斯特拉算法)主要是用于求解有向图中单源最短路径问题.其本质是基于贪心策略的(具体见下文).其基本原理如下: (1)初始化:集合vertex_set初始为{sourc ...
- 非负权值有向图上的单源最短路径算法之Dijkstra算法
问题的提法是:给定一个没有负权值的有向图和其中一个点src作为源点(source),求从点src到其余个点的最短路径及路径长度.求解该问题的算法一般为Dijkstra算法. 假设图顶点个数为n,则针对 ...
- 单源最短路径算法——Bellman-ford算法和Dijkstra算法
BellMan-ford算法描述 1.初始化:将除源点外的所有顶点的最短距离估计值 dist[v] ← +∞, dist[s] ←0; 2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V ...
随机推荐
- 注册带有Portal功能的DYN365_ENTERPRISE_PLAN1地址
使用官方进入的注册页面注册后试用,发现没有Portal功能. https://trials.dynamics.com/Dynamics365/Signup 使用以下的地址注册可以产生Portal ht ...
- 从输入url到显示网页发生了什么
原文链接:https://juejin.im/post/5bf23afa6fb9a049be5d1494 在浏览器中输入url到显示网页主要包含两个部分: 网络通信和页面渲染 互联网内各网络设备间的通 ...
- eclipse中导入dtd文件实现xml的自动提示功能
以mybatis为例 1.mybatis的xml文件头: (1)config文件: <?xml version="1.0" encoding="UTF-8" ...
- 2017年值得一看的7个APP设计
新媒体时代蓬勃发展,各类APP如雨后春笋般出现.下载到合适的APP,不仅衣食住行一键搞定,甚至健身.社交.阅读等需求也能足不出户地满足.对于广大“吃瓜群众”来说,选择APP是个人需求以及跟随潮流的选择 ...
- $.post 提示错误: Uncaught SyntaxError: Unexpected token :
$.post("addRecommond",{"productId":productId,"categoryCode":categoryCo ...
- 浅析10种常见的黑帽seo手法
虽然博主并不认同黑帽seo手法,但是一些常见的黑帽手法还是需要了解的,增加自己对黑帽的认知,也可以在自己优化网站时适时的规避开这些黑帽手法,从而避免自己的网站被搜索引擎惩罚.好了,话不多说,下面进入今 ...
- 2018.10.23 NOIP模拟 “新”的家园(缩图+dijksta/spfa)
传送门 考试70分骗分写挂了=30分=全场最低. 哎今天230垫底了. 这题出的挺好. 对于非关键点直接缩点. 每次把要查的insertinsertinsert进缩好的图里面跑spfa/dijkstr ...
- 2018.09.26洛谷P3957 跳房子(二分+单调队列优化dp)
传送门 表示去年考普及组的时候失了智,现在看来并不是很难啊. 直接二分答案然后单调队列优化dp检验就行了. 注意入队和出队的条件. 代码: #include<bits/stdc++.h> ...
- 2018.08.02 洛谷P3355 骑士共存问题(最小割)
传送门 这题让我联想到一道叫做方格取数问题的题,如果想使摆的更多,就要使不能摆的更少,因此根据骑士的限制条件建图,求出至少有多少骑士不能摆,减一减就行了. 代码: #include<bits/s ...
- 2018.07.30 cogs2632. [HZOI 2016] 数列操作d(线段树)
传送门 线段树基本操作 区间加等差数列,维护区间和. 对于每个区间维护等差数列首项和公差,易证这两个东西都是可合并的,然后使用小学奥数的知识就可以切掉这题. 代码: #include<bits/ ...