【算法描述】
程序直接或间接调用自身的编程技巧称为递归算法。
【主要思想】把大型复杂的问题一步一步的转化为一个与原问题相似规模的较小的问题来求解。就是把一个不能或不好解决的大问题转化为一个或几个小问题,再把这些小问题进一步分解成更小的小问题。
【关键步骤】
分析问题找出大问题与小问题之间的关系,写出他们的前后关系式。然后最关键的是找出递归的定义和递归的终止条件。
这种算法的效练很低,一般不用。
这是之前写过的递归的总结 递归算法总结
还有一些经典的例题,能帮助理解递归的思想
1.【菲波那契数列】 http://ybt.ssoier.cn:8088/problem_show.php?pid=1201
2.【Pell数列】http://ybt.ssoier.cn:8088/problem_show.php?pid=1202
3.【汉诺塔问题】http://ybt.ssoier.cn:8088/problem_show.php?pid=1205
4.【放苹果】http://ybt.ssoier.cn:8088/problem_show.php?pid=1206
5.】求最大公约数问题】http://ybt.ssoier.cn:8088/problem_show.php?pid=1207
【基本概念】
在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心。
【注意】贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。
这是之前对贪心进行的总结 贪心算法总结
还有一些写过的题目的题解
1.贪心题目
2.寻找平面上的极大点
3.拼点游戏
4.A and B and Team Training
5.Cinema Line
6.BerSU Ball
7.Chewbaсca and Number
8.Random Teams
9.Color the Fence
10.Anton and currency you all know
11.Kyoya and Colored Balls
我感觉dp这部分是很困难的,当时学习的时候没少下功夫
【基本思想】
将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
【解题步骤】
1、判断问题是否具有最优子结构性质,若不具备则不能用动态规划
2、把问题分成若干个子问题
3、建立状态转移方程
4、找出边界条件
5、将已知边界值带入方程
6、递推求解
dp代码量一般较少,但是思维量很大,需要很强的逻辑思维能力,我觉得数学功底一定要扎实,最关键的就是找到递推公式
1.线性dp
顾名思义,就是在线性区间上去解决问题,即线性区间上的最优化问题。这是最基础的,主要理解好问题的子问题来写出转移方程,确定的边界条件就ok了
经典题目:
https://blog.csdn.net/SDAU_LGX/article/details/105186003
2.区间dp
就是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的区间中哪些元素合并而来有很大的关系。
主要思想就是在小区间进行 DP 得到最优解,然后再利用小区间的最优解合并求大区间的最优解。往往会枚举区间,将区间分成左右两部分,再求出左右区间进行合并操作
3.背包问题
问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。
也可以将背包问题描述为决定性问题,即:在总重量不超过W的前提下,总价值是否能达到V?
a.01背包
【概述】
0-1背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成0-1背包问题求解。
特点:每种物品仅有一件,可以选择放或不放。
b.完全背包
它的特点就是物品不限量
c.多重背包
它是上面的两种情况的综合,给出了数目的限制。
一些题目的题解
1.https://blog.csdn.net/SDAU_LGX/article/details/105587960
2.https://blog.csdn.net/SDAU_LGX/article/details/105639454
1.二分
【概述】
二分查找又称折半查找,其要求线性表中的记录必须按关键码有序,且必须采用顺序存储。
其基本思想是:用给定值 k 先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据 k 与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。
while(high - low > 1.0e-6)||(left<=right)
{
mid = (high + low)/2;
if(Caculate(mid)<x)
low=mid;
else
high=mid;
}
不过二分很少单独考察,都是结合着其他的一些知识来运用,主要是优化时间
经典题目及题解
https://blog.csdn.net/SDAU_LGX/article/details/105813615
2.三分
【概述】
三分法是二分法的扩展,其用于求凸性或凹形函数的极值,当通过函数本身表达式并不容易求解时,就可以用三分查找来不断逼近求解。
其原理为:函数中存在一个点 x 是最值,对于 x 的左边,满足单调上升(下降),右边满足单调下降(上升),然后进行两次二分,使得不断的逼近这个 x 点,最后求得答案。
【基本思想】
类似二分的定义 Left 和 Right,对于 [L,R],先找出 lmid,紧接着再找出 rmid,然后比较两者谁更优,然后舍去不优的。
mid=Left+(Left-Right)/3
mid_mid=Right-(Right-Left)/3
若 lmid 靠近极值点,则 Right=rmid,若 rmid 靠近极值点,则 Left=lmid;
若在三分过程中,遇到 f(lmid)=f(rmid) 时,若函数严格单调,那么令 left=lmid 或令 right=rmid 均可,若函数不严格单调,即在函数中存在一段函数值相等的区间,将无法判断定义域左右边界该如何缩小,三分法也就不再适用。
数论,是专门研究整数的纯数学的分支,是知识量非常庞大的一部分,这部分也非常难掌握,需要很扎实的数学基本功,对数学能力要求非常非常高
有很多很多的知识需要掌握
筛选法—埃氏筛法(Eratosthenes筛选法)求素数
埃氏筛法分解因数
最大公约数GCD欧几里得算法
最小公倍数的计算
快速幂
费马小定理
欧拉定理
欧拉定理的推论
裴蜀定理
扩展欧几里得算法
逆元及求解
容斥原理
欧拉函数
线性同余方程
中国剩余定理
数论这里就贴一个大佬写的博客 数论知识点
1.string类
string类是c++中的字符串类型。
【头文件】
#include
【输入方式】
主要输入方式有两种,分别为cin和getline
1.cin
string s;
cin>>s;
注:cin输入的字符串不能含空格
2.getline
string s;
getline(cin,s);
【各种简单操作】
string s1, s2; //定义两个字符串对象
string s3 = "Hello, World!"; //创建s3,并初始化
string s4("I am ");
s2 = "Today"; //赋值
s1 = s3 + " " + s4; //字符串连接
s1 += " 5 "; //末尾追加
cout << s1 + s2 + "!" <<endl; //输出字符串内容
【常用功能函数】
string s;
s.size()//返回字符串的长度
s.empty()//判断字符串是否为空 若空,返回ture
在string对象中,可用运算符比较两个字符串的大小
两个string相等意味着它们的长度相同,并且所包含的字符也完全相同
字符串的大小关系依照字典顺序定义且区分大小写字母
string s1 = "hello";
string s2 = "hello world"; // s2 > s1
string s3 = "Hello"; // s3 < s1, s3 < s2
像字符数组那样,下标运算符可以访问string对象中指定位置的字符
2.栈(stack)
【描述】
栈是一种特殊的数据结构,遵循先进后出的原则,只能在栈顶操作元素
【头文件】
#include
【定义】
stack
如
stack<int>s;
【基本功能函数】
empty() //返回bool型,表示栈内是否为空 (s.empty() )
size() // 返回栈内元素个数 (s.size() )
top() //返回栈顶元素值 (s.top() )
pop() // 移除栈顶元素(s.pop(); )
push(data_type a) // 向栈压入一个元素 a(s.push(a);
3.队列(queue)
【描述】
队列是一种先进先出的数据结构,从底端加入元素,从顶端取出元素
【头文件】
#include
【定义】
queue
例如
queue<int>q;
【常用功能函数】
empty() //返回bool型,表示queue是否为空 (q.empty() )
size() //返回queue内元素个数 (q.size() )
front() //返回queue内的下一个元素 (q.front() )
back() // 返回queue内的最后一个元素(q.back() )
pop() // 移除queue中的一个元素(q.pop(); )
push(data_type a) // 将一个元素a置入queue中(q.push(a)
4.动态数组(vector)
【头文件】
#include
【定义】
vector
例如
vector<int>v;
【常用功能函数】
empty() // 返回bool型,表示vector是否为空 (v.empty() )
size() // 返回vector内元素个数 (v.size() )
push_back(data_type a) //将元素a插入最尾端
pop_back() //将最尾端元素删除
v[i] //类似数组取第i个位置的元素(v[0])
5.优先队列(priority_queue)
【描述】
优先队列是一个拥有权值观念的queue,自动依照元素的权值排列,权值最高排在前面
【头文件】
#include
【定义】
priority_queue
例如
priority_queue<int>q
【常用功能函数】
q.push(elem) //将元素elem置入优先队列
q.top() //返回优先队列的下一个元素
q.pop() //移除一个元素
q.size() //返回队列中元素的个数
q.empty() //返回优先队列是否为空
ACM课程到现在已经结束了,回想起第一堂课听到费老师讲课和对ACM的憧憬,仿佛就在昨天。还记得当初ACM新生赛轻轻松松拿了个一等奖,于是信心满满地选了这门课。直到上了几次课把基础的地方学完开始进阶的时候,瞬间感受到什么叫ACM…… 感受到智商碾压。
在我看来,ACM的本质就是数学,数学素养真的很重要,我因为本身数学不是太好,所以有些地方理解起来比较吃力,于是有些题目一遍一遍的WA,有时候真有种欲哭无泪的感觉。期间有好几次觉得太难而想要放弃,但最终还是坚持下来。
一学期的课程让我学到了很多知识,让我养成了很多好习惯。同时也意识到了自己很多的不足。现在就接触了一些基础的算法知识,到大二就会轻松很多;还有刷题,提高了编程能力,感觉自己的写代码的速度明显的提高了。我也养成了很多好的习惯,比如写博客,然后慢慢的其他的科目也会每周都复习一下知识,写一个总结;还有由于题目都是英文的,所以每天都会背单词;也提升了信息查找的能力,学会了怎么在网上准确快速的查找信息。当然我也清楚,如果以后还想在这条路上走下去,这些知识是远远不够的,只是学习了一些基础知识,才达到刚刚入门的程度。
再说说codeforces上的比赛,刚开始打的时候每场比赛也就是出一道题,分数刷刷的往下掉,打到现在,出题的速度也比之前快了不少,平均每场比赛能出2-3题,分数也开始回升,能明显感受到自己的进步,觉得之前的努力没有白费。
ACM课程虽然已经结束了,但学习还远没有结束。ACM课程让我意识到自己现在所接触到的只是知识大海的冰山一角,还有大把知识供我学习、领悟,我要做的就是虚心求教,沉心学习。
革命尚未成功,同志仍需努力!!
最后,感谢费老师这一学期的淳淳教导,您辛苦了!!