ACM课程的总结

没想到时间真的好快,十几周的时间就这样过去了,仅仅在上网课,老师的样子都没见过呢,哈哈。其实自己感觉非常的幸运能够选择这一门课程,特别是在这种特殊的时期吧,感觉自己很懒散,而这门课程,恰恰能够逼着自己去做题,看知识,打比赛,渐渐地自己也就适应了这种环境。感觉在acm这门课程里,学到了可能大学里面不会学到的知识,感觉自己也充实了许多,下面让我来整理下学的知识吧。

一.基本思想和方法知识

这部分的学习过程就是由递归→贪心→dp(动态规划)→背包→二分三分→数论。我会对这些进行逐一总结的。
1. 递归
(1)递归算法:程序直接或间接调用自身的编程技巧称为递归算法。
(2)递归的关键思想:把大型复杂的问题一步一步的转化为一个与原问题相似规模的较小的问题来求解。就是把一个不能或不好解决的大问题转化为一个或几个小问题,再把这些小问题进一步分解成更小的小问题。
(3)递归的关键:分析问题找出大问题与小问题之间的关系,写出他们的前后关系式。然后最关键的是找出递归的定义和递归的终止条件。
(4)自己做过的 部分例题的链接
①分解因数(递归)
②递归周总结这个总结里面写了一些经典且重要的例题像:全排列问题,半数集问题,还有一个感觉比较难理解的放苹果的问题❤(划重点!)。
(5)感想:这一部分的感觉就是利用递归函数,由外到内进行,然后到了最内部,就会得到小问题的答案,然后再返回去,这样问题就解决了,讲实话这部分的题大部分都不是很难,但是还是需要掌握递归的思想,在一些时候也会用到,虽然有的时候效率不是很高。
2. 贪心
(1)基本概念:在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心。每次做出的选择都是“贪”!
注意贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。
(2)关键就是要贪心,每次都是最优解 进而构成问题的最优解
(3)贪心例题链接:这些都是我在做题的时候出现问题的题目或者是一些自己不会没思路的题目的链接。Airconditioner,Silent Classroom,sweeteating,贪心小结(1),贪心小结(2),Flowers,H - Number of Ways,07:Sunscreen,频点游戏(类似于赛马 划重点~~~),Pearl Pairing,D - Anton and currency you all know,Standard Free2play
贪心小结(3),均分纸牌i,活动选择+整数区间;
下面网站是之前老师让做题的网页链接:贪心题目网页
(4)贪心是一种思想并不是做题的方法,这种思想不是只会出现在特定题目里,在打cf的时候前几个题基本都是贪心,可以看得出来贪心这种基本思想还是挺有用的。
3.DP动态规划

动态规划是分阶段求最优值的算法。动态规划的话分为两大块,线性dp+区间dp
动态规划问题的一般解题步骤
1、判断问题是否具有最优子结构性质,若不具备则不能用动态规划。
2、把问题分成若干个子问题(分阶段)。
3、建立状态转移方程(递推公式)。
4、找出边界条件。
5、将已知边界值带入方程。
6、递推求解。
我理解的就是先写出来 数组 然后找出递推公式
动态规划问题,相较于贪心和搜索来说,一个显著的特点就是代码量很少,一个贪心或者搜索问题,一般都会有五六十行代码,而一个DP问题的代码量,往往就十几行甚至更短,以至于真正的核心就那么一行递推公式。但这并不代表DP问题就简单,做DP问题需要很强的逻辑思维和思考能力

①线性dp:
(1)线性dp:就是在线性区间上去解决问题,即线性区间上的最优化问题。学这里的东西我感觉主要要理解好问题的子问题来写出转移方程,,还有弄清具体的边界条件就行了。
(2)关键就是分析题目通过前后关系,找出状态转移方程就行了,问题的难点就是状态方程怎么找!!!!
(3)一些例题和错题链接:最长公共子序列和最大字段和和最长不下降序列 这个链接里 三种经典序列的题 。
Boredom(dp题),合唱队形+登山,摘花生+最低通行费用,dp题目小结1,dp小结2,机器分配,挖地雷+导弹拦截
VJ练习题网页:dp-VJ
②区间dp
(1)区间dp这类题要抓住区间,把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值。
几种模型,这部分题目很多都是类似于这些代码模型;仅仅是改变几个地方

memset(dp,0,sizeof(dp))//初始dp数组
for(int len=2;len<=n;len++){//枚举区间长度
    for(int i=1;i<n;++i){//枚举区间的起点
        int j=i+len-1;//根据起点和长度得出终点
        if(j>n) break;//符合条件的终点
        for(int k=i;k<=j;++k)//枚举最优分割点
            dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);//状态转移方程
    }
}
第二种模型就是根据匹配信息把区间划分成[i+1,k-1][k+1,j]
for (int len = 2; len <= n; len++)
    {
        for(int i = 1, j = len; j <= n; i++, j++)
        {
            dp[i][j] = dp[i+1][j];
            for (int k = i; k <= j; k++)
                if((a[i]=='('&&a[k]==')') || (a[i]=='['&&a[k]==']'))
                    dp[i][j] = max(dp[i][j], dp[i+1][k-1] + dp[k+1][j] + 2);
        }
    }
    printf("%d\n",dp[1][n]);

(2)这个是VJ的练习题网页的链接→VJ区间dp。
→区间dp小结,这里也包含了几个例题个错题→区间dp小结2
总之 对于dp这部分学得时间应该算是最长的吧,这个也是最难掌握的,重点还是要根据题意快速推断出地推关系公式。

4.背包问题
这一个专题也是老师专门挑出来讲解的,这个也算是dp的范围,背包问题很有特点所以拿出来专门讲解。
(1)
0 1背包
0 1背包最显著的特点就是数量确定 just one!
(2)完全背包
它的特点就是物品不限量
(3)多重背包
它就是上面的两种情况的综合就是物品数目没这么理想了,给出了数目的限制。
这三个是最基本的类型,然后在做题的时候其他的像什么二维背包
经典例题Buy the souvenirs链接→第四个还有那个分组的背包问题也是需要注意的地方;
(4)背包例题题目的链接→背包问题小结和VJ网页练习题链接→VJ背包
在这部分 自己同样也犯了许多的错误在背包问题上
像老师强调过的初始化的问题 我没想到;其次就是你要分析出来这个是背包问题,很多时候他不是直接给你“背包”“物品”;这个需要你去分析题意!

5.二分
(1)二分法:是一种算法,其输入是一个有序的元素列表(必须是有序的),如果查找的元素包含在列表中,二分查找返回其位置。这种算法能够大大缩短时间。显然二分二分每次都是在中间看,然后每次都折中!
重点:应用二分法一定得是有序的啊!
(2)

二分法代码基本都是这样 设左区间left 右区间 right
while(high - low > 1.0e-6)||(left<=right)
{
	 mid = (high + low)/2;
    if(Caculate(mid)<x)
        low=mid;
    else
        high=mid;
}
不同的题目 最后结果的形式不一样 有的是输出left 有的是输出 right 视情况而定!

(3)下边就是自己总结过的错题之类的东西
链接→二分法的应用,
二分的VJ题目VJ,
链接→错题总结

二分这部分还是不多难的,但是他也会扩展的 例如老师讲解过三分算法,在这里也简单说下吧。 当需要求某凸性或凹形函数的极值,通过函数本身表达式并不容易求解时,就可以用三分法不断逼近求解。类似二分的定义Left和Right
mid = (Left + Right) / 2
midmid = (mid + Right) / 2;
如果mid靠近极值点,则Right = midmid;
否则(即midmid靠近极值点),则Left = mid;
一般三分法都是非常非常数学的那种。

6.数论
大佬的总结链接。
最后一部分就是数论,数论,是专门研究整数的纯数学的分支,这部分是超级超级难掌握的一节,如果结论你知道,那么做题就非常简单,但是如果你不知道其中的结论的话,恐怕以我的数学能力很难做出来这种题目,感觉这部分的数学推导能力要求非常非常高,很多时候我看着别人的题解,晕头转向的,还是自己刷的题目不够多!
自己就简单列出来数论的结论小结吧

筛选法—埃氏筛法(Eratosthenes筛选法)求素数
埃氏筛法分解因数
最大公约数GCD欧几里得算法
最小公倍数的计算
快速幂
费马小定理
欧拉定理
欧拉定理的推论
裴蜀定理
扩展欧几里得算法
逆元及求解
容斥原理
欧拉函数
线性同余方程
中国剩余定理

这些结论的代码就不先在这里列出了,自己在以前的博客中也写过数论的代码总结,总之这些数论的结论都是非常重要的,就像来事说过 数论的题目以及思想在大赛里面非常容易体现。链接→
VJ练习题
小结1。
数论的结论以及思想不是容易掌握,很多时候你需要真的明白并且能够在题意中能找出结论使用的位置!这部分也是自己掌握比较差的地方吧。
—————————————————————————————————
以上是第一部分吧,自己简单地把之前的博客以及老师讲解的知识汇在一块。
—————————————————————————————————

二.写一下一些小知识点吧

在学这门课程里老师也多次提到了stl之类的知识吧 自己也在这里简单地写写吧。
1.STL的基本用法
自己原本想在这里都写一下来着,自己有篇博客写了这个stl的一些用法
附上链接
点我~~~~~~~~~~~~~~~

就是栈 队列 vector map 等等一些的用法
在stl这方面,让我认识到了原来容器不光是数组一种,而且这里的每一个都有他的优点特点,对于一些复杂的题目,恰恰这些东西能够提供捷径!
2.小知识
其实在学习过程中老师都是旁敲侧击,在代码中使用新东西,其实我们都明白,老师就是想让我们见识广,多查查资料,从而掌握住一些知识吧。
然后我自己也新建了一篇文章,我会把以后代码用的小知识放到博客中
像一些小知识:π的表示方法 宏定义的使用 ,定义无限大的数字,二进制的使用,long long的简洁定义等等
→→→→→→→→→→→→→小知识

第三部分

  1. 在这一部分我想谈一下自己对于acm这们课程的感想吧。自己在选择这门课称之前自己犹豫过,当时怕自己完成不了这门课程的学习,有点担心挂科,但是很幸运,我最后还是选择了这门课程,因为这门课程恰好出现在一个特殊的时期(放假),而这门课恰恰为我提供了学习的动力吧,因为自从到了大学,对于代码的认识仅仅停留在课本上,偶尔老师会在oj上布置任务,然后自己接触代码的时间也不长,但是学acm的时候,大部分的时间都是在刷题,老师也多次强调让我们刷题。首先在写代码上,感觉自己的写代码的速度提高了,并且自己的代码头文件也变多了,以前头文件就一两个,现在用到的头文件非常多,感觉自己的见世面也会渐渐地扩大。而且不选acm和选了acm在这个学期的差距一定会拉开的,选了acm真的学到了很多很多大学老师不会讲的东西和知识点,一些简便做题的方法和知识!
  2. 通过ACM这门课程,其实自己学到了不光是知识这一点,还有很多方面,比如,老师之前专门让我们写博客,其实渐渐地自己也就适应了写博客,感觉也没这么大的压力,渐渐地自己的csdn博客就成了自己的错题集和知识本,并且这个平台也为自己解决不会的问题提供了渠道。
  3. 其次就是很多的做题的平台 像codeforce,牛客,VJ,洛谷等等这些都是在acm课里的收获,通过这些平台真的真的能锻炼自己写代码的能力和思维。
    如果没参加acm这门课程的话,不知道什么时候才会在这上面做题呢。并且有些题目全英语,感觉对自己的英语词汇提供了帮助。感觉这些平台也让我见识到了“人外有人天外有天”,自己涉及的不过是一些基础。自己也明白了,现在老师讲的内容都是一些基础,真正的ACM还得需要个人去探索未知。还有通过ACM上面做题,真的是磨性子,一道题目可能得做上几天才能出来答案,这个过程是无比煎熬的,题目WR TL等等都是见惯了,也是让自己抓狂。
    4.也是遇到了非常负责的老师,老师知道我们懒,就专门“逼着”我们去做题干一些事情,后来发现这些对自己的帮助很大,也是很感谢老师!自己也在acm中交到了很多的一起学习的同学,之间互相探讨帮助。师父领进门修行看个人,老师现在只是把我们领上了路,以后可能不会再受到老师的教诲了,但是我依然会坚持做题,继续去扩宽自己的视野提高自己的能力,不辜负老师的付出!

以上就是我对ACM课程的全部总结,最后用老师们常说的一句话来画上句号吧!你自己怎么学都是为了自己!本事才是自己的!

你可能感兴趣的:(ACM课程的总结)