本学期的算法分析与设计课程分为理论课和实验课两个部分。理论部分,通过学习各种算法分析方法,对常见的问题进行算法的设计与求解;实验部分,通过上级实验,对各种常见问题的算法进行实现。通过本课程的学习,对常见的算法分析与设计的方法有了更加深刻的理解。
学习算法,首要的问题是:什么是算法?通俗的讲,就是一步步正确解决问题的方法和策略。本课程的学习,就是学习这些方法和策略,以达到求解未知问题目的。算法求解问题的步骤具有输入、输出、确定性、有穷性的性质。对于待求解的问题,需要要输入输出和严格的描述。问题的描述针对该问题的所有实例,是通用的描述,而计算机每次求解只是针对一个实例求解。如果一个算法能应用于问题的任意实例,并保证得到正确解答,称这个算法解答了该问题。
问题的求解过程主要分为腋下几个步骤:
- 提出问题,问题具有输入输出和严格的描述。
- 分析问题,用数学描述问题,运用数学工具,建立数学模型。
- 运用算法设计思想解决问题。
- 选择数据结构设计算法,设计出求解问繁体的步骤,是问题求解的核心。
- 证明正确性。证明算法在有穷步内终止并且对于一切合法的输入都能得到满足要求的结果。
- 分析算法。分析算法的复杂性。
- 实现算法
- 调试程序。
同一个问题,选择不同的模型,不同的数据结构,会具有不同的算法。如何选择一个好的算法,需要对算法进行分析。衡量一个算法的好坏,需要看算法使用资源的多少,而计算机中的资源,最主要的是时间和空间资源,算法分析,主要是进行算法时间复杂度的分析,时间复杂度就是算法运行的时间,衡量算法的效率。
算法复杂度由大O记号表示,它与问题的规模n有关,记为O(n)。其分为几个数量级:常数量级,对数量级,线性量级,多项式量级,指数量级和阶乘量级。对于算法复杂度的学习是由排序问题的算法引入的,不同的排序算法和时间复杂度如下图所示:
算法设计技术也称策略,是求解问题的有效策略,是算法解题的一般性方法。常用的设计策略有:枚举、递归、贪心、分治、动态规划。
枚举法又叫暴力求解法,是基于问题描述和定义,简单直接地解决问题的方法。从问题所有可能的解集中一一枚举各元素。用题目中给定的约束条件判断是否符合条件,查找特殊属性(目标函数最优)的元素。
算法步骤:
- 构造问题的所有可能解(解空间,找出解的表示形式)。
- 逐个评价解,选出满足约束条件的元素
- 逐个评价解,选出满足约束条件的元素
贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性(即某个状态以后的过程不会影响以前的状态,只与当前状态有关。)
递归算法,是直接或间接调用自身的算法。使用递归杉树实现。
递归函数的要素是边界条件和递归方程,这也是递归设计的要点。
递归一般用于解决三类问题:
- 数据的定义是按递归定义的。
- 问题解法按递归实现的。
- 数据结构按递归定义的。
动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的。若用分治法来解这类问题则分解得到的子问题数目太多,以至于最后解决原问题需要耗费指数时间然而,不同子问题的数目常常只有多项式量级。在用分治法求解时,有些子问题被重复计算了许多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,从而得到多项式时间算法。为了达到此目的,可以用一个表来记录所有已解决的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填人表中。这就是动态规划法的基本思想。具体的动态规划算法多种多样,但它们具有相同的填表格式。
动态规划算法适用于解最优化问题。通常可按以下4个步骤设计:
(1)找出最优解的性质,并刻画其结构特征。
(2)递归地定义最优值。
(3)以自底向上的方式计算出最优值。
(4)根据计算最优值时得到的信息,构造最优解。
以上内容为算法分析与设计课程的学习内容总结,其中对于动态规划的学习和掌握哦还存在许多困难。在学习各种算法问题的过程中,对于具体算法的具体实现上存在许多不足,原因是缺少相应的练习,
通过本课程度学习,对编程求解问题的步骤和方法有很多启发。比如具体算啊的实现是依赖于具体的数据结构的,所以还需加强对数据结构的学习。
在学习的过程中,掌握的比较好的算法是Dijkstra单源最短路径算法。从数据结构的选择,算法的设计与描述,程序设计的实现都有比较深刻的理解。
首先是数据结构的选择,Dijkstra算法是图算法,数据结构的实现上选择了邻接矩阵。具体实现如下:
const int maxn = 510;
typedef struct
{
int num_v;
int num_e;
int edge[maxn][maxn];
int source;
int d[maxn];
} Graph;
算法流程的设计实现如下:
void Dijkstra()
{
for (int i = 0; i < g.num_v;i++) {
g.d[i] = INF;
}
g.d[g.source] = 0;
priority_queue<i_pair, vector<i_pair>, greater<i_pair> > Q;
Q.push(make_pair(g.d[g.source], g.source));
while (!Q.empty()) {
int u = Q.top().second;
Q.pop();
for (int v = 0; v < g.num_v; v++) {
if (g.edge[u][v] == INF) continue;
if (g.d[v] > g.d[u] + g.edge[u][v]) {
g.d[v] = g.d[u] + g.edge[u][v];
Q.push(make_pair(g.d[v], v));
}
}
}
}