学期总结

来源:互联网 发布:ubuntu映射网络文件夹 编辑:程序博客网 时间:2024/06/04 19:53

学期总结

 学了这门课让我掌握了很多知识,一些打代码的简便方法,和有关算法,还有数据结构的知识,其实最重要的是学会了思考问题的方式。

              在这一个学期的学习中,我学习了好多关于acm竞赛的算法知识,这些算法知识,有难有易,掌握的有快有慢,但不论如何,都能明白,因为不明白的可以直接把过程模拟一遍,这样对过程了解加深,做题就得心应手了,但这样一般也是只能做些简单的题。

              我在学习完一个专题后,一般先明白这个算法的意思和实现途径,然后再把老师讲的例题(并且在要完成的习题中出现的类型的)做一遍,打一遍代码,熟悉一遍过程,明白那个地方容易出错,那个地方容易漏掉,那个地方是难点。记住这些经验,再来攻克一些老师没讲过,但难度较小的题。当做了不少此类专题的题后,再攻克有难度的题,一步步,慢慢深入下去,差不多就能对这个专题的问题掌握了。

              但毕竟人力有限,过了很长时间后,总会忘掉这些经验,这些方法,这些技巧。幸亏老师让我们写博客,这就解决了这个问题。于是,在哪道题上总结了经验,教训,我都会在代码后面,或思路里写出来,以后如果忘掉的话,可以看一看,回忆一下,有时候,没时间总结写下这些经验,我以后一般也会补上。当然,肯定会有忘记的时候,人毕竟有失误的时候。

             最重要的,学了这门课,思考问题的思路广了,以前可能会在一条路上走下去,但现在,由于在做acm题时,在一条路上走不下去的时候,还有其他的方法,就会换一种思路,换一种算法,这种不行下一种。于是,在平常思考问题时,也会这样想,这样在学习其他知识点的时候就会轻松许多。

             由于我看过大二的数据结构和离散数学,里面有图论的内容,在学数据结构的时候,它里面很多地方理解都要用到递归,两种搜索的思想,我感觉老师讲到那里的时候也应该会讲这部分内容吧,这样,我就相当于提前学了,可以节省一部分学这些的时间,哈哈,这只是我认为的,不知道实际教学的时候会怎么样。

             这些就是我的一些收获和感想,当然,收获有很多,有无形的,还有有形的,不能一一概述了。接下来,我就总结了一下这学期学习的主要内容,有的只是重点,当然可能不全,这就留着以后复习之用吧。

一.stl

stl是很多容器的使用。

1.栈。

先进后出,只能从一队元素的后面加元素或者是删除元素。

栈的头文件:include <stack>。

定义:stack<date_type>stack_name。

主要操作有:empty()------返回bool类型,表示栈内是否为空(s.empty())。

                     size()--------返回栈内元素个数。(同上)。

                      top()---------返回栈顶元素。

                      pop()-------移除栈顶元素。

                    push()------向栈内压入一个元素。

2.队列


像现实中队列一样,先入先出,从队列的后面加元素,从队列的前面删除元素。
头文件:#include<queue>
定义:queue<date_type>queue_name
主要操作:empty()——————返回bool类型,表示队列是否为空。
size()——————返回队列中的元素个数。
front()——————返回队列中第一个元素。
back()——————返回队列中最后一个元素。
pop()——————移除队列中第一个元素。
push()——————把一个元素放入队列的最后。

3.vector

动态数组又名向量。
不用定义向量的大小,直接放到里面就行,它会自动申请空间。
头文件:#include<vector>
定义:vector<date_type>vector_name
主要操作:
empty() ------------- 返回bool型,表示vector是否为空 (v.empty() ) 

 size() ------------ 返回vector内元素个数 (v.size() ) 

 push_back(data_type a) ----------将元素a插入最尾端 

 pop_back() ----------将最尾端元素删除 v[i] 类似数组取第i个位置的元素 

 4.sort

稳定排序。排序函数。经常会使用,通常会重载cmp()函数。
头文件: #include <algorithm> 

定义:sort(begin开始排序的位置, end排序结束的位置); sort(begin, end, cmp);
主要操作: 

1) sort(num, num + 5);
//默认从小到大排序num[] = {1,2,5,6,9};
2) bool cmp(int a, int b){m
return a > b; }
sort(num, num + 5, cmp);
//从大到小num[] = {9,6,5,2,1};

5.upper_bound 和 lower_bound 

找出一个数列中,相同大小元素的上下限。
upper_bound(begin, end, value); ---------- 返回>value的元素的第一个位置。

 lower_bound(begin, end, value);---------- 返回>=value的元素的第一个位置。

 例子: 

num[6] = {1,2,2,3,4,5}; 

lower_bound(num, num + 6, 2)为num + 1

 upper_bound(num, num + 6, 2)为num + 3

6.set 和 multiset 集合。

可以自动把放入其中的元素进行排序(从小到大)。
set是不会有重复的元素。
multiset可以有重复的元素。
头文件: #include <set> 

定义:set <data_type> set_name;
主要操作: s.insert(elem) -- ----------安插一个elem副本,返回新元素位置。

 s.erase(elem) ------------ 移除与elem元素相等的所有元素,返回被移除的元素个数。

 s.erase(pos) ------------ 移除迭代器pos所指位置上的元素,无返回值。

 s.clear() ------------ 移除全部元素,将整个容器清空。 

 迭代器举例:

 multiset <int> :: iterator pos; for
(pos=s.begin(); pos != s.end(); pos++) ... ...

7.map和multimap

映射。
也是一种集合,不过是一组值放入集合中,一个值为关键值,一个为实值。
按照关键值排序。并且有和数组类似的性质,m[key] = value。
头文件: #include <map>

 定义:map<data_type1,data_type2>map_name; 

如:
map <string, int> m;//默认按string由小到大排序 

主要有用的操作: 

m.size() --------------------返回容器大小 

m.empty()-------------------- 返回容器是否为空

 m.count(key)-------------------- 返回键值等于key的元素的个数

 m.insert(elem) --------------------插入一个元素elem 

a)运用value_type插入
map<string, float> m; 

m.insert(map<string, float>:: value_type ("Robin", 22.3));

 b) 运用pair<>

 m.insert(pair<string,float>("Robin", 22.3)); 

 c) 运用make_pair()

 m.insert(make_pair("Robin", 22.3)); 

8.优先队列(priority_queue)

 一个拥有权值观念的queue,自动依照元素的权值排列,权值最高排在前面。缺省情况下,priority_queue是利用一个max_heap完成的。
头文件: #include <queue> 

定义:priority_queue <data_type> priority_queue_name;

 如:priority_queue <int> q;//默认是大顶堆

 主要操作:

 q.push(elem) --------------------将元素elem置入优先队列 

 q.top() --------------------返回优先队列的下一个元素 

 q.pop() --------------------移除一个元素 

 q.size() --------------------返回队列中元素的个数

 q.empty() --------------------返回优先队列是否为空

二.递归递推。

递归

递归是大问题转化为小问题,不断调用自身或不断间接调用的一类算法。
1.。递归算法的关键是要找出大问题和小问题的联系----即递归定义。进而使大问题的规模不断减少,从而达到能解决的规模,最后解决这个问题。
2.。递归算法的另一个关键点是递归终止条件,即使得这个递归调用结束的条件。

递推

递推和递归非常相似。
递推是把问题划分为若干个步骤,每个步骤之间,或者是这个步骤于之前的几个步骤之间有一定的数量关系,就可以用前几项的值表示出这一项的值,这样就可以把一个复杂的问题变成很多小的问题。
递推问题的关键是要设出状态变量,并且表示出递推公式,找出这两点,这个问题就可以说解决了。
递推算法注意的是设置什么样的递推状态,因为一个好的递推状态可以让问题很简单。
而一般最难的是想出递推公式,一般递推公式是从后面向前想,倒推回去,当然也有很多是从中间想或者是前面,一项一项的推到最后。

小技巧:

1...有时,递归算法的效率会很低,这时候就可以用记忆化搜索,即建立一个标志数组为全局变量,用来记录每次递归得到的答案,这样如果后面要继续使用这个值的时候,就不用在计算了,避免了重复计算。
2...有时候递推也会用预处理的方法,在处理的数据比较大时,想把所有的数据算出来,然后再开始不断调出。

三.动态规划

主要定义:

1...动态规划是一种解决最优化问题的方法,动态规划最大的特点是变化多端,解题方法不是按照一定套路来的。
2...动态规划一般是能分阶段的问题,可以把大问题转化为小问题,充分利用计算机重复处理问题的特点,把这个问题解决掉。并且动态规划中的变量都是有一定含义的,每个变量都有它所包含的意思,比如:在最长上升子序列这个题中,dp[n]代表了以第n个数结尾的最长子序列的长度。最重要的是动态规划问题要有状态转移方程,这个方程不一定是数学公式,有时候是前后之间的某种关系,一般能够推出公式的题都是比较简单的,难得是找不到一个公式。
3....动态规划有两个原理,最优化原理和无后效性原理,最优化原理指的是一个阶段的最优解要能导致全局的最优。无后效性原理是当前的最优解确定了,不会再受到其他变化的影响,只与推出它来的状态转移方程有关。

解题一般步骤:

1.分阶段
2.确定变量的状态,其实我感觉分阶段和确定变量状态没有谁先谁后,有时候是一起想出来的。
3.找出状态转移方程(不一定是公式)。
4.确定边界条件。。因为状态转移一般是公式,所有要有结束条件。

ps:做了很多动态规划题,感觉这种题的核心代码都是循环结构,一般是两重循环,还有三重的。毕竟动态规划是要不断重复计算嘛。

四.动态规划的背包问题

实际上这个专题应该个动态规划合起来的。

有三种基础背包问题 :01背包,完全背包,多重背包,
还有一些复杂了一些的背包问题:混合了前面三种背包的背包问题,分组背包,有两个价值的背包,背包方案数问题。

01背包

n个物品放在容量为v的背包里,第i个物品的价值是c[i],体积是w[i]。每件物品只能拿一次。
这就是01背包,红色字体是它和其他基础背包问题的区别。
背包问题一般都有“套路”,也就是相同背包问题大部分的思路代码差不多。
dp[i][j]表示第i个物品放在容量为j的背包里的最大价值。
比如01背包就是两重循环
for int i=1......n
for int j=n.....w[i]
循环里面就是最关键的状态转移方程。

完全背包

n个物品放在容量为v的背包里,第i个物品的价值是c[i],体积是w[i]。每件物品可以拿无限次。
也是两重循环。
for int i=1......n
for int j=w[i].....n

多重背包

n个物品放在容量为v的背包里,第i个物品的价值是c[i],体积是w[i]。每件物品可以拿有限次。
还是两重循环,不过在里面有次数的限制,可以再加一层循环,或者设置一个计算物品次数控制变量。
这两重循环和多重背包一样。
剩下的背包问题都是在这三种背包基础上的变形,只要掌握了这三种背包,其他的背包仔细思考一下也能解决。

小技巧:

1...动态规划问题可以用滚动数组的方法节省空间,动态规划问题中,尤其是背包问题 ,有很多都是用前一状态的变量推出后一状态的变量,这就可以用滚动数组的方法来节省空间。就是二维数组可以用一维数组来代替,因为另外一维本来就是记录状态的作用。

2....二进制思想,在多重背包问题中可能要用到,每个数都可以用多个2的n次方来表示,比如26=2^4+2^3+2^1.这样就可以把一个数变成多个数,把多重背包的一个物品变成01背包的多个物品。就可以按照01背包的思想做题了。

3.....在动态规划中有很多题可以用递归函数做,也可以用递推公式加双重循环做,一般数据量大的用递推公式,小的可以用递归函数,有些很多并且要处理多组数据的也可以加上预处理,记忆化搜索什么的。

五..二分贪心

二分

二分指的是一种搜索的方法,主要有三个数,left,rest,mid,先判断mid这个值符合不符合。
诺符合,则使得left=mid,否则rest=mid。
上面说的是一般的二分方法。但我们用的时候,一般都不是这么用。
如果是二分题,一般会有两个成反比的变量a,b,一般会知道一个确定的值a,然后b就是要二分的值,这就需要使得b不断逼近可能的值,使得a等于已知的值。
这是一般的二分题的套路。
但二分题思路都比较简单,主要是精度问题,有些题对精度要求比较高,有的要求四舍五入,有的不要求。这个一不注意就会出错。

贪心

贪心最重要的是贪心标准。找到贪心标准就好办了。
贪心是解决动态规划题的一种简便方法,一般贪心题也可以用动态规划解决。
贪心也是求最优解的问题,但这种题一般不需要考虑整体的最优解状况,只需考虑局部最优解就可以。
怎么选择出局部的最优解就是贪心标准,按照这个标准,不断选择下去,就会得出整体的最优解。
动态规划一般是两重循环,而贪心只需一重循环就够了。
但是,一般的贪心题虽然循环数减少了,但出题人会出的比较复杂,让你找不到贪心标准或者贪心标准要写很多代码,有很多细节需要处理。

六.搜索

广度优先搜索:

1...顾名思义,就是搜索的范围比较广,它运用了队列的相关知识。
就是如果有一个大山,有很多层,从山顶有很多路通往下一层,如果有一个人是从第一层开始找,找完第一层再找第二层,依次下去,这就是广度优先搜索。
如果学过数据结构中的树,则就是从树的根部开始找,先找下一层的各个结点,然后再下一层的结点,一直持续下去。

2....一般广度优先搜索用一个队列来盛放要搜索的内容,每搜索完一个内容后,把这个内容的后续要搜索的内容再放入队列。
在这里可能会用到很多关于结构来盛放很多的变量,因为一般是有一个队列,如果太多会超时,但有时候变量不是一个,直接把一个结构体放入队列比较方便。
3...一般这里也会用到重载运算符,或者是sort()函数的cmp函数重载。

深度优先搜索:

1...它运用了递归的知识。
2...就是如果有一个大山,有很多层,从山顶有很多路通往下一层,如果有一个人是从第一层开始找了一条路开始找,一直顺着这条路找到底,再找第二条路,这就是深度优先搜索。如果用数据结构的树来说,就是从根部开始先选择一条路去下一层的一个节点,再从该结点,选择一条路去下一个结点,慢慢深度下去,回溯上来后再从该结点选择其他结点搜索下去。
3...一般深度优先搜索用递归函数来实现。大部分思路差不多,每个题的差别在进入下一层递归的 递归条件上 和 递归结束条件上。
4...但是写这种程序的时候,一定不要忘了回溯,还有回溯的时候,有一些标记的符号要还原,这些忘了就会出错。

七.数据结构--图论的知识

图论的知识没做题,只说两个算法吧。

一.最短路径问题

1..最简单的解决最短路径的算法(floyed-warshall算法)

这种算法时间复杂度高,可以解决出现负边权的问题。

这个算法有三重循环。

第一重-----循环的中间点k

第二重第三重------循环的起点终点 i 共和 j 

算法的思想:如果 i 点到 k 点的距离加上 k 点到 j 点的距离小于原来 i 点到 j 点的距离,那么就用这个跟段的路径来代替原来的路径长度。

核心代码:

for(k=1,;k<=n;k++)

    for(i=1,;i<=n;i++)

            for(j=1,;j<=n;j++)

                    if(dis[i][j]>dis[i][k]+dis[k][j])dis[i][j]=dis[i][k]+dis[k][j];

其中dis【】【】是两个点之间的距离。

2..spfa算法。

主要思想:

先将起点入队列,每次从队列中去除一个元素,病对与它相邻的点进行修改(即有了比原先更短的距离),就将其入队,不断循环下去,直到队列为空。

这个思想其实和广度优先搜索很相似。

代码我就不打了。但这个无法解决有负权回路的情况。因为他这是在不断循环,试想,如果一段回路的边权都是负的,那么,距离会越加越小,也就是每次都会修改距离,然后入队,就会无穷无尽下去。

二.并查集的最小生成树的问题

krusal算法

主要思想:

把所有的点当成一块一块的互不连接的连通块。然后枚举所有的边权,当这个边是连接了两个互不连接的块时,就把权值加进去,并把这两个合并到一起(即加入最小生成树),直到选取了n-1条边的时候结束。

核心代码:

for(i=1;i<=m;i++)

if  //这是一条u,v不属于同一集合的边(u,v)(因为前面已经排序,所以必为最小)

{1.合并u,v所在集合,即把它们加入最小生成树。

2.sum+=w(u,v);//w(u,v)是边的权值。

3.k++;//计算这是第几条边。

4.如果k=n-1,说明结束了,break;


}

sum就是最小生成树的总权值之和。

八.数论

数论里都是一些数学知识。

主要有:

1.判断并找出素数。

2.找出最小公倍数,最大公约数。

3.数学中的各种关于面积,体积,求交点,求积分,求导,的运算。

4.高精度计算,卡特兰数。

5.欧拉函数。

这些主要是要记好基本公式,需要时要把答案的公式推出来。高精度要记好模板,或者用Java做,当然有人要用模板。

这些就是我这一学期的总结了。


原创粉丝点击