ACM课程学习总结报告html
经过一个学期的ACM课程的学习,我学习了到了许多算法方面的知识,感觉到了算法知识的精彩与博大,以及算法在解决问题时的巨大做用。此篇ACM课程学习总结报告将从如下方面展开:算法
学习ACM算法知识以前的具有的知识基础数组
学习过程及知识梳理数据结构
心得体会及收获函数
一,学习ACM算法知识以前具有的知识基础学习
在开始这一学期的课程以前,大一上学期及寒假期间我学习了C++标准库中的STL,了解了一些通用操做,各类类型的容器的特性,以及一些算法。关于算法,只学习了一些简单的遍历,递归。并未深刻学习。优化
二,学习过程及知识梳理htm
1. 递归对象
递归并非在ACM课上学习的,是在C++的课上获得了讲解。写在这里是由于我觉的递归是很重要的一种方法或者说思想。在上学期我本身了解了一下递归,自觉得已经掌握了递归。在这一学期开始深刻了解以后发现有一些有趣的地方。排序
首先,递归的具体含义是:递归_计算机科学(来自维基百科)。
这篇文章说的很清楚:
递归是经过重复将问题分解为同类的子问题而解决问题的方法
具体在C/C++中,是指在函数中调用函数自己。
在我看来,递归与循环有类似之处,都是下一轮与上一轮进行一样的操做,因此有时候递归能够与循环相互转化。但循环与递归也有不一样之处,循环是单向的,递归有一个返回过程,并且,递归是从结果出发的,方向不一样;另外,递归能够用于在计算开始不肯定层数的状况,而循环则不能够;
我以为这句话说的很好:
递归的强大之处在于它容许用户用有限的语句描述无限的对象。所以,在计算机科学中,递归能够被用来描述无限步的运算,尽管描述运算的程序是有限的。
——尼克劳斯·维尔特
但我认为在C/C++中能够用循环(递推)的地方应该避免用递归,由于C/C++中的递归每产生新的一层运算就要产生新的堆栈,这无疑下降了效率。
这也是我在刚开始学习的时候以为递归无用的缘由,但在后面的学习中,我发现有不少算法用递归来理解更加容易方便,更接近数学。好比在搜索的相关算法的学习中,递归实现就重要。
2.贪心算法与动态规划
贪心与动态规划有许多类似之处
费老师在一开始讲贪心时就说,贪心是最容易的算法了,贪心的题目也是可遇不可求的。。。。贪心理解是一种在每一步选择中都采起在当前状态下最好或最优(即最有利)的选择,从而但愿致使结果是最好或最优的算法。适用于子问题的最优解组成了最终问题的最优解的状况,也就是说具备最优子结构的问题。
贪心算法的经典模型:
(1)背包问题(最优装载):
给定n个物品和一个容量为C的背包,物品i的重量是Wi,其价值为Vi,背包问题是如何选择入背包的物品,使得装入背包的物品的总价值最大。
在背包问题中能够将物品的一部分装入背包,但不能重复装入。
背包问题的贪心原则就是尽量选择单位重量价值最大的物品。
解决背包问题时首先按照物品的”性价比“(Vi/Wi)由大到小排序,而后顺序选择物品直至背包装满。
(2)区间相关问题
区间问题是可抽象为多个线段之间的关系的一类问题,不一样的类型的区间相关问题有着不一样的贪心原则,具体在程序上就表如今线段区间的不一样排序方式以及可行区间的筛选方式。
就我刷过的题目来看,区间相关问题模板化很强,基本只要将问题抽象成区间(线段)之间
的关系,运用不一样的排序原则及不一样的贪心原则选择可行区间便可。
3.搜索
搜索是很重要的一种算法,应用范围很广,并且在以后图论的学习中是很关键的知识点,在刘汝佳的紫书中是将搜索放在了图论专题之下,不少资料也是将搜索做为图论的一个子专题。
老实说,个人搜索掌握的很差。因此正好趁写这个报告的机会,将搜索专题总结复习一下。
搜索分为DFS(深度优先搜索),BFS(广度优先搜索)(BFS与DFS对图进行搜索),此学期ACM课程还介绍了两种方法二分法与三分法;
(1)BFS
搜索完一层以后才进行下一层的搜索工做,队列的先进先出性质可很好的实现BFS。
首先将队首元素(未到达节点)取出;拓展此节点并经拓展后产生的新节点放入队列(没法产生新节点则直接删除队首元素);删除队首元素;循环进行以上步骤直至队列为空
BFS找到的问题的解必定是最优解。
下面是广搜的伪代码,BFS是一种层次遍历,无需用到递归便可方便的实现:
While 队列不为空 do
Tmp <- 队首元素
从Tmp循环拓展下一个状态Next
If 状态Next合法 then
生成新状态Next
Next.Step = Tmp.Step + 1
将Next放入队列
End
删除队首元素
End
广度优先遍历演示地址:
http://sjjg.js.zwu.edu.cn/SFXX/sf1/gdyxbl.html
(2)DFS
DFS是按照从初始状态生成下一层的任一节点,判断目标状态是否出现;若未出现,返回上一层继续上一步骤,直至不能产生新的状态的节点;若仍不能找到目标状态,则返回上一层,至上一层的下一个节点继续扩展;重复以上步骤,直至找到目标状态。
相较于BFS,DFS能够更快的找到目标状态,但有时找到的解不必定是最优解
很明显DFS运用了递归的思想,能够运用递归来实现
DFS的递归实现与非递归实现都运用了栈的先进先出的性质,相似于BFS利用队列来实现,DFS利用栈来实现的思路是:
1 每次取出栈顶元素,对其进行拓展。
2 若栈顶元素没法继续拓展,则将其从栈中弹出。继续1过程。
3 不断重复直到得到目标状态(取得可行解)或栈为空(无解)。
具体的实现的伪代码为:
非递归实现:
While 栈不为空 do
Tmp <- 栈顶元素
从Tmp拓展下一个未拓展的状态Next
If 没有未拓展状态(到达叶节点) Then
删除栈顶元素
Else If 状态Next合法 Then
将Next压入栈
End
递归实现:
Function Dfs (Int Step, 当前状态)
Begin
可加结束条件
从当前状态循环拓展下一个状态Next
If 状态Next合法 Then
Dfs (Step + 1, Next ))
End
(3)二分搜索与三分搜索
二分搜索与三分搜索的原理都很简单,即不断缩小搜索区间,直至找到解
二分搜索要求搜索对象单调且无重复;
三分搜索是在二分搜索的基础上对右区间或左区间再进行一次二分,适用于凸性函数,便是该函数必须有一个最大值(或最小值),在最大值(最小值)的左侧序列,必须知足不严格单调递增(递减),右侧序列必须知足不严格单调递减(递增)。
为了提升效率,二分搜索与三分搜索通常使循环实现,不使用递归
4.动态规划
就我而言,这学期最难的一块内容就是动态规划了,只要问题有具备最优子结构就可以使用动态规划来解决。使用动态规划解决问题的过程当中,最关键的无疑是找到子问题的分解方式与状态转移方程了。有的简单问题能够递推直接解决这两个问题,而有关一些复杂的问题,能够找到许多经典模型:
(1)背包类问题
背包类问题的范围很大,从最基础的01背包与彻底背包,衍生出许许多多的背包类问题。《背包九讲》写的很好,给了我很大启发。具体的思路与代码实现就不在此报告里赘述了。背包问题的变化很丰富,要注意分辨清楚
( 2 ) 最大递增子序列与最长公共子序列
最大递增子序列问题的状态转移方程为:F(k) = Max { F(i); 1<i < k 且 a[i] < a[k] } + 1
最长公共子序列的递推公式为
5.图论
图论与dp是这学期最大的两个专题了。在这一专题里,首先了解了图数据结构的一些基础知识以及图的存储方式,我感到最有趣的就是邻接表的数组表示形式了,开销低且高效,感受甚是神奇,下面贴出邻接表的数组表示形式:
struct edge
{
int x, y, nxt; typec c;
} bf[E];
void addedge(int x, int y, typec c)
{
bf[ne].x = x; bf[ne].y = y; bf[ne].c = c;
bf[ne].nxt = head[x]; head[x] = ne++;
}
基础知识学习了解以后,又学习了并查集,经过对并查集实现的按部就班的一次次优化,越发感受到思考的力量,我以为这是这学期ACM课程中最有趣的一部分了。
学习完了并查集,又学习了最小生成树的几种经典算法:prim算法,kruskal算法
及解决最短路问题的三种算法:Dijkstra算法,Bellman-Ford算法,spfa算法(Bellman-Ford算法的队列实现)
至此,这学期的ACM课程就结束了。
三,心得体会及收获
收获固然是以上提到的算法知识了,体会到了算法是颇有趣的,更重要的是初步学习到了如何解决问题(不敢说彻底学习到了。。。)。这东西比较虚,但在作应用软件时,明显体会到了学过ACM或者说算法的优点:不只仅给我增长了自信,思考问题也更加深刻,同时代码实现的能力也好一些。
除了以上这些,经过ACM课程我还认识了许多比本身强,比本身努力的人;也经过各类渠道了解到了山农以外的牛人是多么牛。我意识到本身以前看到的那片天空是多么眇小,为那些不能称之为成绩的“成绩”而沾沾自喜是多么幼稚;这给了我努力的动力与静下心来的理由。这或许是对我改变最大的一点吧。
2016年6月30日
刘占山