算法设计与分析--回溯法哈密尔顿回路问题
回溯算法的应用
课程名称:算法设计与分析院系:
学生姓名:
学号:
专业班级:
指导教师:
年月日
回溯算法的应用
摘要:回溯法是在包含问题的所有解的解空间树(或森林)中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否满足问题的约束条件。如果满足进入该子树,继续按深度优先的策略进行搜索。否则,不去搜索以该结点为根的子树,而是逐层向其祖先结点回溯。其实回溯法就是对隐式图的深度优先搜索算法。
回溯法是一个既带有系统性又带有跳跃性的的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。
回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。这就是以深度优先的方式系统地搜索问题解的回溯算法,它适用于解决一些类似n皇后问题等求解方案问题,也可以解决一些最优化问题。关键词:回溯法解空间树深度优先搜索
目录
第1章绪论 (1)
1.1 回溯算法的背景知识 (1)
1.2 回溯法的前景意义 (1)
第2章回溯算法的理论知识 (2)
2.1 回溯算法的基本思想 (2)
2.2 回溯算法设计过程 (2)
2.3回溯算法框架 (2)
2.4 回溯算法的一般性描述 (4)
第3章哈密尔顿问题 (5)
3.1 问题描述 (5)
3.2 问题分析 (5)
3.3 算法设计 (5)
3.4 测试结果与分析 (7)
第4章结论 (11)
参考文献 (12)
第1章绪论
1.1 回溯算法的背景知识
回溯算法是尝试搜索算法中最为基本的算法,在递归算法中,其存在的意义是在递归知道可解的最小问题后,逐步返回原问题的过程。实际上是一个类似于枚举的搜索尝试方法,他的主题思想是在搜索尝试的过程中寻找问题的解,当发现不满足条件时就回溯返回,尝试别的路径。
简单的说就是:从问题的某一种初始状态出发,依次搜寻每一种可能到达的情况,当走到这条路的“尽头”时,回过头到上一个情况,看这个情况是否还有没有走过的路,依次进行下去,直到遍历完所有的情况。
回溯法实际上是一种深度优先搜索的方式。对于回溯法解决的问题,通常将其解空间组织成图或者树的形式。对于用回溯法求解的问题,首先要将问题进行适当的转化,得出状态空间树。这棵树的每条完整路径都代表了一种解的可能。通过深度优先搜索这棵树,枚举每种可能的解的情况;从而得出结果。但是,回溯法中通过构造约束函数,可以大大提升程序效率,因为在深度优先搜索的过程中,不断的将每个解与约束函数进行对照从而删除一些不可能的解,这样就不必继续把解的剩余部分列出从而节省部分时间。
1.2 回溯法的前景意义
在做题时,有时会遇到这样一类题目,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题。回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。
通过运用回溯法,可以解决很多问题,譬如我们所熟知的“八皇后问题”、“0/1背包问题”,这只是在教学阶段中的运用,在实际运用中回溯法也能起到很大的作用。
回溯法适用于解决难以归纳一般规律解法的问题,其适用范围广,灵活性大,在解一些列举方法的问题时尤其可用。但是,其缺点也是明显的,即时间复杂度较大;因此在采用时我们应该因情况的不同而做出不同的选择。
第2章回溯算法的理论知识
2.1 回溯算法的基本思想
回溯法是在包含问题的所有解的解空间树(或森林)中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否满足问题的约束条件。如果满足进入该子树,继续按深度优先的策略进行搜索。否则,不去搜索以该结点为根的子树,而是逐层向其祖先结点回溯。其实回溯法就是对隐式图的深度优先搜索算法。
2.2 回溯算法设计过程
(1)确定问题的解空间
应用回溯法解问题时,首先应明确定义问题的解空间。问题的解空间应至少包含问题的一个(最优)解。
(2)确定结点的扩展规则,如每个皇后在一行中的不同位置移动,而象棋中的马只能走“日”字等。
(3)搜索解空间
回溯算法从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。这个开始结点就成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为一个新的活结点,并成为当前扩展结点。如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。
2.3回溯算法框架
(1)问题框架
设问题的解是一个n维向量(a1,a2,.....,an),约束条件是ai(i=1,2,3, ....,n)之间满足某
种条件,记为f(ai)。
(2)非递归回溯框架
int a[n],i;
初始化数组a[];
i=1;
While(i>0(有路可走))and([未到达目标]) //还未回溯到头
{ if(i>n)//搜索到叶结点
搜索到一个解,输出;
else //正在处理第i个元素
{ a[i]第一个可能的值;
while(a[i]在不满足约束条件且在搜索空间内)
a[i]下一个可能的值;
if(a[i]在搜索空间内)
{标识占用的资源;
i=i+1;} //扩展下一个结点
else
{清理所占的状态空间;//回溯
i=i-1;}
}
}
(3)递归算法框架
回溯法是对解空间的深度优先搜索,在一般情况下用递归函数来实现回溯法比较简单,其中i为搜索深度,框架如下:
int a[n];
try(int i)
{if(i>n)
输出结果;
else
for(j=下界;j<=上界;j++)
if(f(j))
{a[i]=j;
...
try(i+1);
回溯前的清理工作(如a[i]置空值等);
}
}
2.4 回溯算法的一般性描述
回溯法的一般描述
可用回溯法求解的问题P,通常要能表达为:对于已知的由n元组(x
1,x
2
,…,x
n
)
组成的一个状态空间E={(x
1,x
2
,…,x
n
)∣x
i
∈S
i
,i=1,2,…,n},给定关于n元
组中的一个分量的一个约束集D,要求E中满足D的全部约束条件的所有n元组。其中
S i 是分量x
i
的定义域,且 |S
i
| 有限,i=1,2,…,n。我们称E中满足D的全部约束条
件的任一n元组为问题P的一个解。
解问题P的最朴素的方法就是枚举法,即对E中的所有n元组逐一地检测其是否满足D的全部约束,若满足,则为问题P的一个解。但显然,其计算量是相当大的。
我们发现,对于许多问题,所给定的约束集D具有完备性,即i元组(x
1,x
2
,…,
x i )满足D中仅涉及到x
1
,x
2
,…,x
i
的所有约束意味着j(j<=i)元组(x
1
,x
2
,…,
x j )一定也满足D中仅涉及到x
1
,x
2
,…,x
j
的所有约束,i=1,2,…,n。换句话说,
只要存在0≤j≤n-1,使得(x
1,x
2
,…,x
j
)违反D中仅涉及到x
1
,x
2
,…,x
j
的约束
之一,则以(x
1,x
2
,…,x
j
)为前缀的任何n元组(x
1
,x
2
,…,x
j
,x
j+1
,…,x
n
)一
定也违反D中仅涉及到x
1,x
2
,…,x
i
的一个约束,n≥i≥j。因此,对于约束集D具有
完备性的问题P,一旦检测断定某个j元组(x
1,x
2
,…,x
j
)违反D中仅涉及x
1
,x
2
,…,
x j 的一个约束,就可以肯定,以(x
1
,x
2
,…,x
j
)为前缀的任何n元组(x
1
,x
2
,…,
x j ,x
j+1
,…,x
n
)都不会是问题P的解,因而就不必去搜索它们、检测它们。回溯法正
是针对这类问题,利用这类问题的上述性质而提出来的比枚举法效率更高的算法。
第3章哈密尔顿问题
3.1 问题描述
回溯搜索解哈密尔顿问题:
哈密尔顿回路就是指经过图(有向图或无向图)中所有顶点一次且仅一次的通路。
3.2 问题分析
用回溯算法遍历哈密尔顿回路中的所有顶点(每个顶点遍历一次且仅一次),回溯法是采用深度优先遍历的算法,对解空间树进行遍历。在求哈密尔顿回路时,要用一个二维数组存储顶点的邻接矩阵,并且要对已经访问过的顶点进行标记。
3.3 算法设计
(1) 算法分析
用回溯法求解哈密尔顿回路问题,首先要画出问题的解空间树,该解空间树是一棵最大度是n的树(其中n为图中的顶点数),树中只有第一个结点的度为n,其余的结点的度都为n-1(该结点不用与其自身相连)。在编写算法时,可以通过判断该边在图的邻接矩阵中的值来剪枝,如果其值不是1,则说明该边不存在,则剪枝不用继续搜索。由于在求图的哈密尔顿回路时,走过的顶点不能再重复走,所以要对已经遍历过的顶点做一个标记,如果在搜索时找到的是一个带有标记的顶点,那么该路径也是不可行的,应剪去。
(2) 实例分析
创建一个有6个顶点,9条边的连通图,如下图所示,求解哈密尔顿回路的所有解。
图3-1哈密尔顿回路
此实例共有6种解,分别为:
回路1:1 2 6 5 3 4
回路2:1 2 6 5 4 3
回路3:1 3 2 6 5 4
回路4:1 3 4 5 6 2
回路5:1 4 3 5 6 2
回路6:1 4 5 6 2 3
(3) 数据结构
1> 在求解哈密尔顿回路问题时,需要用graph[][]二维数组存储边的邻接矩阵。
2> 数组x[]存储回路的解。
(4)流程图
图3-2 哈密尔顿回路算法设计主函数流程图
图3-3 哈密尔顿回路算法设计hamiltonian()函数流程图
图3-4 哈密尔顿回路算法设计nextvalue()函数流程图3.4 测试结果与分析
1、有哈密尔顿回路测试结果:
图3-5有哈密尔顿回路连通图边的创建
创建6个顶点,9条边的连通图。在提示的信息下输入顶点号,以便创建边。
图3-6有哈密尔顿回路连通图的解
如图3.5以及图3.6所示,创建有6个顶点,9条边的有哈密尔顿回路的连通图,则哈密尔顿回路的所有解共有6种。回溯算法是按照深度优先的原则对哈密尔顿回路连通图进行遍历,因此在一个具有哈密尔顿回路的连通图中会有多种不同的回路。
2、无哈密尔顿回路测试结果:
图3-7无哈密尔顿回路连通图的解
创建5个顶点,6条边的连通图,输入不同顶点号以创建边,在第6条边创建完后,从图3-7中可以看到没有输出解,这是由于创建的连通图中没有哈密尔顿回路,所以没有解答案。
第4章结论
通过本次课程设计,我对算法设计与分析的基础有了更清楚的认识,基本掌握了回溯算法求解一般哈密尔顿回路的基本思想以及编程原理,提高了程序开发能力,切实体会到了算法设计与分析在编程中的指导作用,对提高自身的编程能力以及项目制作能力有很大的意义。在这次的实例求解哈密尔顿回路问题,我对回溯法求解问题的思想有了进一步的理解,也对回溯算法理解的更加透彻。由于对哈密尔顿回路问题的知识了解的不多,对程序设计有很大的阻碍,因此,只能通过上网查询,以及向同学询问,并且多加思考,才完成了本次的程序设计。
利用回溯算法求解哈密尔顿回路问题,需建立在连通图的基础上,哈密尔顿回路就是遍历图中的所有顶点,但要求每个顶点只能经过一次且仅一次。回溯算法是在解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。利用递归算法,使大规模问题逐步小化为小规模问题,程序设计框架更加清晰,简单,算法设计也更加明了。
回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。用回溯算法解决问题的一般步骤为:
1、定义一个解空间,它包含问题的解。
2、利用适于搜索的方法组织解空间。
3、利用深度优先法搜索解空间。
4、利用限界函数避免移动到不可能产生解的子空间。
问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。
具体来说:确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。这个开始结点就成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为一个新的活结点,并成为当前扩展结点。如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。
参考文献[1] 算法设计与分析(第二版)吕国英主编
算法设计与分析王晓东
习题2-1 求下列函数的渐进表达式: 3n^2+10n; n^2/10+2n; 21+1/n; logn^3; 10 log3^n 。 解答:3n^2+10n=O(n^2), n^2/10+2^n=O(2^n), 21+1/n=O(1), logn^3=O(logn), 10log3^n=O(n). 习题2-3 照渐进阶从低到高的顺序排列以下表达式:n!,4n^2,logn,3^n,20n,2,n^2/3。 解答:照渐进阶从高到低的顺序为:n!、3^n、4n^2 、20n、n^2/3、logn、2 习题2-4 (1)假设某算法在输入规模为n时的计算时间为T(n)=3*2^n。在某台计算机上实现并完成该算法的时间为t秒。现有另外一台计算机,其运行速度为第一台计算机的64倍,那么在这台新机器上用同一算法在t秒内能解输入规模为多大的问题? (2)若上述算法的计算时间改进为T(n)=n^2,其余条件不变,则在新机器上用t秒时间能解输入规模多大的问题? (3)若上述算法的计算时间进一步改进为,其余条件不变,那么在新机器上用t秒时间能解输入规模多大的问题? 解答:(1)设能解输入规模为n1的问题,则t=3*2^n=3*2^n/64,解得n1=n+6 (2)n1^2=64n^2得到n1=8n (3)由于T(n)=常数,因此算法可解任意规模的问题。 习题2-5 XYZ公司宣称他们最新研制的微处理器运行速度为其竞争对手ABC公司同类产品的100倍。对于计算复杂性分别为n,n^2,n^3和n!的各算法,若用ABC公司的计算机能在1小时内能解输入规模为n的问题,那么用XYZ公司的计算机在1小时内分别能解输入规模为多大的问题? 解答:n'=100n n'^2=100n^2得到n'=10n n'^3=100n^3得到n'=4.64n n'!=100n!得到n' 《数据结构》必须掌握的知识点与算法 第一章绪论 1、算法的五个重要特性(有穷性、确定性、可行性、输入、输出) 2、算法设计的要求(正确性、可读性、健壮性、效率与低存储量需求) 3、算法与程序的关系: (1)一个程序不一定满足有穷性。例操作系统,只要整个系统不遭破坏,它将永远不会停止,即使没有作业需要处理,它仍处于动态等待中。因此,操作系统不是一个算法。 (2)程序中的指令必须是机器可执行的,而算法中的指令则无此限制。算法代表了对问题的解,而程序则是算法在计算机上的特定的实现。 (3)一个算法若用程序设计语言来描述,则它就是一个程序。 4、算法的时间复杂度的表示与计算(这个比较复杂,具体看算法本身,一般关心其循环的次数与N的关系、函数递归的计算) 第二章线性表 1、线性表的特点: (1)存在唯一的第一个元素;(这一点决定了图不是线性表) (2)存在唯一的最后一个元素; (3)除第一个元素外,其它均只有一个前驱(这一点决定了树不是线性表) (4)除最后一个元素外,其它均只有一个后继。 2、线性表有两种表示:顺序表示(数组)、链式表示(链表),栈、队列都是线性表,他们都可以用数组、链表来实现。 3、顺序表示的线性表(数组)地址计算方法: (1)一维数组,设DataType a[N]的首地址为A0,每一个数据(DataType类型)占m个字节,则a[k]的地址为:A a[k]=A0+m*k(其直接意义就是求在数据a[k]的前面有多少个元素,每个元素占m个字节) (2)多维数组,以三维数组为例,设DataType a[M][N][P]的首地址为A000,每一个数据(DataType 类型)占m个字节,则在元素a[i][j][k]的前面共有元素个数为:M*N*i+N*j+k,其其地址为: A a[i][j][k]=A000+m*(M*N*i+N*j+k); 4、线性表的归并排序: 设两个线性表均已经按非递减顺序排好序,现要将两者合并为一个线性表,并仍然接非递减顺序。可见算法2.2 5、掌握线性表的顺序表示法定义代码,各元素的含义; 6、顺序线性表的初始化过程,可见算法2.3 7、顺序线性表的元素的查找。 8、顺序线性表的元素的插入算法,注意其对于当原来的存储空间满了后,追加存储空间(就是每次增加若干个空间,一般为10个)的处理过程,可见算法2.4 9、顺序线性表的删除元素过程,可见算法2.5 10、顺序线性表的归并算法,可见算法2.7 11、链表的定义代码,各元素的含义,并能用图形象地表示出来,以利分析; 12、链表中元素的查找 13、链表的元素插入,算法与图解,可见算法2.9 14、链表的元素的删除,算法与图解,可见算法2.10 15、链表的创建过程,算法与图解,注意,链表有两种(向表头生长、向表尾生长,分别用在栈、队列中),但他们的区别就是在创建时就产生了,可见算法2.11 16、链表的归并算法,可见算法2.12 17、建议了解所谓的静态单链表(即用数组的形式来实现链表的操作),可见算法2.13 18、循环链表的定义,意义 19、循环链表的构造算法(其与单链表的区别是在创建时确定的)、图解 算法设计与分析(第二版)主编:吕国英 习题答案 第四章 1. #include for(i=1;i<=9;i++) { n=(n+2)*2; } printf("%d\n",n); return 0; } 3. #include 哈密尔顿回路算法比较 一、贪心法 贪心法通常用来解决具有最大值或最小值的优化问题。通常从某一个初始状态出发,根据当前局部而非全局的最优决策,以满足约束方程为条件,以使得目标函数的值增加最快或最慢为准则,选择一个最快地达到要求的输入元素,以便尽快地构成问题的可行解。 贪心法通过一系列选择得到问题的解。其所做出的每一个选择都是当前状态下的局部最好选择,即贪心选择。贪心法并不总能得到问题的最优解。 利用贪心法解哈密尔顿回路的C++算法如下: #include "stdio.h" int G[8][8]={{0,2,8,1,9}, {2,0,5,10,9}, {8,5,0,5,3}, {1,10,5,0,5}, {9,9,3,5,0}}; struct Edge //记录边的信息 { int x; int y; int value; //边的权值 }; typedef struct Edge Weight; int T[5]={0}; //用于标识节点是否被遍历过 int P[6]={0}; //存放路径 int sum_value=0; //计算总路径长度 Weight min_value(int r) //找出当前节点具有最小权值的相邻边 { int i,j=0,min; Weight W[5]; //用于存放相邻边的信息 for(i=0;i<5;i++) { if((T[i]==0)&&(i!=r)) //当节点未被遍历且不是自己到自己 { W[j].x=r; W[j].y=i; W[j].value=G[r][i]; //记录相邻边的信息 j++; } } min=W[0].value; for(i=0;i 第1章绪论工程大数电习题答案册工程大数电习题答案 册 2.(1)×(2)×(3)√ 3.(1)A(2)C(3)C 5.计算下列程序中x=x+1的语句频度 for(i=1;i<=n;i++) for(j=1;j<=i;j++) for(k=1;k<=j;k++) x=x+1; 【解答】x=x+1的语句频度为: T(n)=1+(1+2)+(1+2+3)+……+(1+2+……+n)=n(n+1)(n+2)/6 6.编写算法,求一元多项式p n(x)=a0+a1x+a2x2+…….+a n x n的值p n(x0),并确定算法中每一语句的执行次数和整个算法的时间复杂度,要求时间复杂度尽可能小,规定算法中不能使用求幂函数。注意:本题中的输入为a i(i=0,1,…n)、x和n,输出为P n(x0)。算法的输入和输出采用下列方法 (1)通过参数表中的参数显式传递 (2)通过全局变量隐式传递。讨论两种方法的优缺点,并在算法中以你认为较好的一种实现输入输出。 【解答】 (1)通过参数表中的参数显式传递 优点:当没有调用函数时,不占用内存,调用结束后形参被释放,实参维持,函数通用性强,移置性强。 缺点:形参须与实参对应,且返回值数量有限。 (2)通过全局变量隐式传递 优点:减少实参与形参的个数,从而减少内存空间以及传递数据时的时间消耗 缺点:函数通用性降低,移植性差 算法如下:通过全局变量隐式传递参数 PolyValue() { int i,n; float x,a[],p; printf(“\nn=”); scanf(“%f”,&n); printf(“\nx=”); scanf(“%f”,&x); for(i=0;i 算法设计与分析的复习要点 第一章:算法问题求解基础 算法是对特定问题求解步骤的一种描述,它是指令的有限序列。 一.算法的五个特征: 1.输入:算法有零个或多个输入量; 2.输出:算法至少产生一个输出量; 3.确定性:算法的每一条指令都有确切的定义,没有二义性; 4.可行性:算法的每一条指令必须足够基本,它们可以通过已经实现的基本运算执行有限次来实现; 5.有穷性:算法必须总能在执行有限步之后终止。 二.什么是算法?程序与算法的区别 1.笼统地说,算法是求解一类问题的任意一种特殊的方法;较严格地说,算法是对特定问题求解步骤的一种描述,它是指令的有限序列。 2.程序是算法用某种程序设计语言的具体实现;算法必须可终止,程序却没有这一限制;即:程序可以不满足算法的第5个性质“有穷性”。 三.一个问题求解过程包括:理解问题、设计方案、实现方案、回顾复查。 四.系统生命周期或软件生命周期分为: 开发期:分析、设计、编码、测试;运行期:维护。 五.算法描述方法:自然语言、流程图、伪代码、程序设计语言等。 六.算法分析:是指对算法的执行时间和所需空间的估算。算法的效率通过算法分析来确定。 七.递归定义:是一种直接或间接引用自身的定义方法。一个合法的递归定义包括两部分:基础情况和递归部分; 基础情况:以直接形式明确列举新事物的若干简单对象; 递归部分:有简单或较简单对象定义新对象的条件和方法 八.常见的程序正确性证明方法: 1.归纳法:由基础情况和归纳步骤组成。归纳法是证明递归算法正确性和进行算法分析的强有力工具; 2.反证法。 第二章:算法分析基础 一.会计算程序步的执行次数(如书中例题程序2-1,2-2,2-3的总程序步数的计算)。二.会证明5个渐近记法。(如书中P22-25例2-1至例2-9) 三.会计算递推式的显式。(迭代法、代换法,主方法) 四.会用主定理求T(n)=aT(n/b)+f(n)。(主定理见P29,如例2-15至例2-18)五.一个好的算法应具备的4个重要特征: 1.正确性:算法的执行结果应当满足预先规定的功能和性能要求; 2.简明性:算法应思路清晰、层次分明、容易理解、利于编码和调试; 3.效率:算法应有效使用存储空间,并具有高的时间效率; 4.最优性:算法的执行时间已达到求解该类问题所需时间的下界。 六.影响程序运行时间的主要因素: 1.程序所依赖的算法; 2.问题规模和输入数据规模; 3.计算机系统性能。 七.1.算法的时间复杂度:是指算法运行所需的时间; 第一章作业 1.证明下列Ο、Ω和Θ的性质 1)f=Ο(g)当且仅当g=Ω(f) 证明:充分性。若f=Ο(g),则必然存在常数c1>0和n0,使得?n≥n0,有f≤c1*g(n)。由于c1≠0,故g(n) ≥ 1/ c1 *f(n),故g=Ω(f)。 必要性。同理,若g=Ω(f),则必然存在c2>0和n0,使得?n≥n0,有g(n) ≥ c2 *f(n).由于c2≠0,故f(n) ≤ 1/ c2*f(n),故f=Ο(g)。 2)若f=Θ(g)则g=Θ(f) 证明:若f=Θ(g),则必然存在常数c1>0,c2>0和n0,使得?n≥n0,有c1*g(n) ≤f(n) ≤ c2*g(n)。由于c1≠0,c2≠0,f(n) ≥c1*g(n)可得g(n) ≤ 1/c1*f(n),同时,f(n) ≤c2*g(n),有g(n) ≥ 1/c2*f(n),即1/c2*f(n) ≤g(n) ≤ 1/c1*f(n),故g=Θ(f)。 3)Ο(f+g)= Ο(max(f,g)),对于Ω和Θ同样成立。 证明:设F(n)= Ο(f+g),则存在c1>0,和n1,使得?n≥n1,有 F(n) ≤ c1 (f(n)+g(n)) = c1 f(n) + c1g(n) ≤ c1*max{f,g}+ c1*max{f,g} =2 c1*max{f,g} 所以,F(n)=Ο(max(f,g)),即Ο(f+g)= Ο(max(f,g)) 对于Ω和Θ同理证明可以成立。 4)log(n!)= Θ(nlogn)考研数据结构必须掌握的知识点与算法-打印版
算法设计与分析 吕国英 习题答案第四章
哈密尔顿回路问题
最全数据结构课后习题答案(耿国华版[12bb]
最新算法设计与分析复习要点(1)
算法设计与分析习题解答