哈尔滨师范大学
学 年 论 文
题 目 关于贪心算法研究
学 生 ***
指导教师
年 级 2009级
专 业 计算机科学与技术
系 别 计算机科学与技术
学 院 计算机科学与信息工程学院
哈尔滨师范大学
年 月
论 文 提 要
为满足人们对大数据量信息处理的渴望,解决各种实际问题,计算机算法学得到了飞速的发展。设计一个好的求解算法更像是一门艺术而不像是技术。
当一个问题具有最优子结构性质和贪心选择性质时,贪心算法通常会给出一个简单、直观、高效的解法。贪心算法通过一系列的选择来得到一个问题的解。它所作的每一个选择都是在当前状态下具有某种意义的最好选择,即贪心选择;并且每次贪心选择都能将问题化简为一个更小的与原问题具有相同形式的子问题。尽管贪心算法对许多问题不能总是产生整体最优解,但对诸如最短路径问题、最小生成树问题,以及哈夫曼编码问题等具有最优子结构和贪心选择性质的问题却可以获得整体最优解。而且所给出的算法一般比动态规划算法更加简单、直观和高效。
贪心算法设计及其实际应用研究
***
摘 要:在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每
一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心算法。从贪心算法的定义可以看出,贪心法并不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。贪心算法所作的选择可以依赖于以往所作过的选择,但决不依赖于将来的选择,也不依赖于子问题的解,因此贪心算法与其它算法相比具有一定的速度优势。如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。本文讲述了贪心算法的含义、基本思路及实现过程,贪心算法的核心、基本性质、特点及其存在的问题。并通过贪心算法的特点举例列出了以往研究过的几个经典问题,对于实际应用中的问题,也希望通过贪心算法的特点来解决。
关键词:贪心算法;哈夫曼编码;最小生成树;多处最优服务次序问题;删数问题
一、贪心算法的基本知识概述
(一)贪心算法的核心
贪心算法的核心问题是选择能产生问题最优解的最优度量标准,即具体的贪心策略。
贪心策略是指从问题的初始状态出发,通过若干次的贪心选择而得出最优值(或较优解)的一种解题方法。其实,从“贪心策略”一词我们便可以看出,贪心策略总是做出在当前看来是最优的选择,也就是说贪心策略并不是从整体上加以考虑,它所做出的选择只是在某种意义上的局部最优解,而许多问题自身的特性决定了该题运用贪心策略可以得到最优解或较优解。
(二)贪心算法的理论基础
正如前文所说的那样,贪心策略是最接近人类认知思维的一种解题策略。但是,越是显而易见的方法往往越难以证明。下面我们就来介绍贪心策略的理论—拟阵。
“拟阵”理论是一种能够确定贪心策略何时能够产生最优解的理论,虽然这套理论还很不完善,但在求解最优化问题时发挥着越来越重要的作用。
拟阵M定义为满足下面3个条件的有序对(S,I):
(1)S是非空有限集;
(2)I是S的一类具有遗传性质的独立子集族,即若B∈I,则B是S的独立子集,且B的任意子集也都是S的独立子集。空集¢必为I的成员;
(3)I满足交换性质,即若A∈I,B∈I且|A|<|B|,则存在某一元素x∈B-A,使得A∪{x}∈I。
定理1.1 拟阵M中所有极大独立子集具有相同大小。
引理1.1 (拟阵的贪心选择性质)设M=(S,I)是具有权函数M的带权拟阵,且S中元素依权值从大到小排列,又设x∈S是S中第一个使得{x}是独立子集元素,则存在S的最优子集A使得x∈A。
引理1.2 设M=(S,I)是拟阵。若S中元素x不是空集¢的一个可扩元素,则x也不可能是S中任一独立子集A的可扩展元素。
引理1.3 (拟阵的最优子结构性质)设x是求带权拟阵M=(S,I)的最优子集的贪心算法Greedy所选择的S中的第一个元素。那么,原问题可简化为求带权拟阵M'=(S',I')的最优子集问题,其中
S'={y|y∈S且{x,y}∈I}
I'={B|BS-{x}且B∪{x}∈I}
M'的权函数是M的权函数在S'上的限制(称M'为M关于元素x的收缩)。
定理1.4(带权拟阵贪心算法的正确性)高M=(S,I)是具有权函数W的带权拟阵,算法Greedy返回M的最优子集。
适宜于用贪心策略来求解的许多问题都可以归结为在加权拟阵中一个具有最大权值的独立子集的问题,即给定一个加权拟阵M=(S,I),若能出一个独立且具有最大可能权值的子集A,且A不被M中比它更大的独立子集所包含,那么A为最优子集,也是一个最大的独立子集。我们认为,针对绝大多数的信息学问题,只要它具备了“拟阵”的结构,便可用贪心策略求解。拟阵理论对于我们判断贪心策略是否适用于某一复杂问题是十分有效的。
二、贪心算法的C++实现
(一) 哈夫曼算法的实现
哈夫曼算法思路为:
(1)以n个字母为结点构成n棵仅含一个点的二叉树集合,字母的频率即为结点的权。
(2)每次从二叉树集合中出两个权最小者合并为一棵二叉树:
增加一个根结点将这两棵树作为左右子树。新树的权为两棵子树的权之和。
(3)反复进行步骤(2)直到只剩一棵树为止。如图2-1所示。
图2-1 哈夫曼树
哈夫曼树的算法:
template<class T>
BinaryTree<int>HuffmanTree(T f[], int n)
{//根据权f[1:n]构造霍夫曼树
//创建一个单节点树的数组
Huffman <T>*W=newHuffman<T> [n+1];
BinaryTree<int> z,zero;
for(int i=1;i<=n;i++){
z.MakeTree(i, zero, zero);
W[i].weight=f[i];
W[i].tree=z; }
//数组变成—个最小堆
MinHeap<Huffman<T>>Q(1);
Q.Initialize(w,n,n);
//将堆中的树不断合并
Huffman<T> x,y
for(i=1;i<n;i++){
Q.DeleteMin(x);
Q.DeleteMin(y);
z.MakeTree(0, x.tree, y.tree);
x.weight+=y.weight;x.tree=z
Q.Insert(x); }
Q. DeleteMin(x);//最后的树
Q. Deactivate();
delete[]w;
;
算法分析
HuffmanTree初始化优先队列Q需要O(n)。DeleteMin和Insert需O(logn)。n-1次的合并总共需要O(nlogn)。所以n个字符的哈夫曼算法的计算时间为O(nlogn)。
(二) 单源最短路径问题哈夫曼编码树的带权路径长度
问题:给定带权有向图G=(V,E),其中每条边的权是一个非负实数。要计算从V的一点v0(源)到所有其他各顶点的最短路长度。路长指路上各边权之和。
算法思路(Dijkstra):设最短路长已知的终点集合为S,初始时v0∈S,其最短路长为0,然后用贪心选择逐步扩充S:每次在V-S中,选择路径长度值最小的一条最短路径的终点x加入S。
构造路长最短的最短路径:设已构造i条最短路径,则下一个加入S的终点u必是V-S中具有最小路径长度的终点,其长度或者是弧(v0,u),或者是中间只经过S中的顶点而最后到达顶点u的路径。
算法描述:
(1)用带权的邻接矩阵c来表示带权有向图,c[i][j]表示弧<vi,v>上的权值。若<vi,vj>∈V,则置c[i][j]为∞。设S为已知最短路径的终点的集合,它的初始状态为空集。从源点v到图上其余各点vi的当前最短路径长度的初值为:dist[i]=c[v][i] vi∈V
(2)选择vj,使得dist[j]=Min{dist[i]|vi∈V-S},vj就是长度最短的最短路径的终点。令S=SU{j}。
(3)修改从v到集合V-S上任一顶点vk的当前最短路径长度:如果dist[j]+c[j][k]<dist[k]则修改dist[K]=dist[j]+c[j][k]。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论