NOIP来了,好紧张~
以下将这进1年学的东东汇总一下,最后还有临场经验!
【递归】【递推】递归是在学完基础语言过后的第一个“算法”,哎,说白了就是函数调用自身,想当初完全无法理解,有了递归,斐波那契啊,汉诺塔啊都很简单了,这也为后面打下了基础,当然,纯递归也很容易超时,没办法~于是就有了记忆化递归,递推嘛差不多,只是用了for循环,加上数组来算,举个栗子:
/*
记忆化递归解决斐波那契数列
*/
#include<cstdio>
long long a[92];//经测试longlong最多能装下第91个数
long long x(int k)
{
if(k<3)
return k;
if(a[k]==0)
a[k]=x(k-1)+x(k-2);
return a[k];
}
int main()
{
int n;
scanf("%d",&n);
printf("%I64d",x(n-1));
}
#--------------------------------------------------------------------------------#
【回溯】【DFS(深搜)】这种算法就是建立在递归之上的,大体思路就是:找到最深处(冲啊!!!),返回,找第二种,再返回……直到找完,解决得了很多迷宫问题(你最好不要用此算法尝试数据大得恶心的最优解题,不然超时超得你透心凉心飞扬),顺便刷刷阅读量:
#--------------------------------------------------------------------------------#
【BFS(广搜)】
#--------------------------------------------------------------------------------#
【枚举】世上最强骗分技巧,传说中的暴搜就是它了,任何题都可以枚举,依靠计算机那每秒10亿次的超级运算能力,我们每次都能完美地——超时,当然也有题完全可以枚举,事实上只要你有超过3个for循环,基本上是超时了,题型:
【NOIP普及组】2016年模拟考试(11.5)——火柴棒等式
事实上枚举过了很多题,都水得不想写了……╮(╯▽╰)╭,题库
#--------------------------------------------------------------------------------#
【贪心】最好理解的一种较高级算法,不停地找最大的(真是贪婪),最简单的:一个数字矩阵,从每行选一个数,使其和最大。就选每行最大的即可,题型:
#--------------------------------------------------------------------------------#
【DP(动态规划)】和递推很类似(只是类似而已),主要是满足一下条件可以尝试:
1.数据规模不大;
2.像贪心,又没办法贪的(反正就是很恶心的,选最大的不行的题);
3.满足无后效性原则:当前的最优解与后面无关,只与前面有关;
4.满足最优化原理(最优子结构性质):从起始到结束的最优路径中的每个节点都为当前最优;
说这么多,到底怎么“规划”呢?
首先划分阶段,使每一个阶段与前面建立起联系;
然后写出状态转移方程(最难的一步),说白了就是将当前最优解用之前的表示出来,这是一个漫长的过程,熟了一下就行,不熟绞尽脑汁也不知道;
接着需要寻找边界,你总不可能让它无休止地找吧……当然有最后就又开始,一定要注意初始化;
最后就是程序的实现了,这个非常简单,不多说。
题型:
#--------------------------------------------------------------------------------#
【图】
一大波文字来袭,做好心理准备……
首先,图是什么?图就是图,请注意,图就是图,请记住,图就是图!好吧,将点用边连起来的就是图,如下,事实上,图是一种数据结构,但我还是归在了算法~
然后,有几个概念(天哪噜,又有概念了,肿么办!!)
【有向】很好理解,点1可以到点2不代表点2可以到点1就是有向。
【无向】相反,点1可以到点2便代表点2可以到点1。
【权值】一条边的大小(也可能是费用、长度什么的)叫权值。
【结点的度】以此点为终点的边的数目。
【结点的出度】简单点,此点可以出去的边的数目。
【结点的入度】反之,有几个点可以一步到此点,入度就是几。
【回路】从此点出发能回到此点便是回路。
注意以下都是归属于图的
1.【树】
树嘛……以前觉得好深奥,其实,简单点,一个有向无回路图就是树,如上(哇塞,真的好像一棵树诶!!)。
【二叉树(BT)】咳咳……二叉树,理论最多的东西,让我们继续愉(xiang)快(gu)地不聊了吧。
好像还没说二叉树是啥,反正就是每个点的下面的结点(称之为儿子)最多只有2个的树。
好的,关于二叉树有两个东西:完全二叉树和满二叉树。
【满二叉树】除最后一层的结点外,其他的都有两个儿子的二叉树,说起来好吓人,其实很简单。
【完全二叉树】连续的二叉树(好像这解释很智障,但我真的不知道怎么解释了,图中自有真相):
树的题嘛……
可以点这里<--
【堆】这个看这里<--
【最短路径】:最简(bao)单(li)易(chao)懂(shi)的代码:Floyed,稍(bu)微(yi)难(chao)一(shi)点的:Dijkstra,请参看:
【图】最短路径——Floyed算法和Dijkstra算法
如果你想更快,那就上天吧……
好吧,当然有更快的Ford和SPFA,这东西最适合装逼了,当然装逼是有代价的——复杂——想知道自己点击前面。
【并查集】,请看这里<--
图最容易考到的都差不多了,呼……
#--------------------------------------------------------------------------------#
另外的数据结构:
【栈】最形象的比喻:一个杯子,只能从上面进,上面出。什么意思?就是先进去的后出,后进去的先出,如图。
假如有一列数:1,2,3,4,让我们来模拟一下栈:
初始:栈为空。
①1入栈。栈中的数为(从下往上):1;
②2入栈。栈中的数为(从下往上):1,2;
③3入栈。栈中的数为(从下往上):1,2,3;
④4入栈。栈中的数为(从下往上):1,2,3,4;
⑤出栈(只有一种操作,因为你只能取出栈顶元素,不能取出中间的元素):4出栈,栈中的数为(从下往上):1,2,3;
⑥出栈(只有一种操作,因为你只能取出栈顶元素,不能取出中间的元素):3出栈,栈中的数为(从下往上):1,2;
⑦出栈(只有一种操作,因为你只能取出栈顶元素,不能取出中间的元素):2出栈,栈中的数为(从下往上):1;
⑧出栈(只有一种操作,因为你只能取出栈顶元素,不能取出中间的元素):1出栈,栈为空。
就这样了,栈有什么用呢?首先最直观的:逆序输出一列数,当然你可以用数组,但是……一会再讲。
事实上,递归就是栈的使用,只不过是一层存了很多条代码,而不是只存一个数。
装逼程序(逆序输出):
#include<cstdio>
bool f=1;
void go(int x)
{
if(scanf("%d",&x)==1) go(x);
if(f) {f=0; return;}//因为用无个数的输入,所以要处理一下
printf("%d ",x);
}
int main()
{
int a;
go(a);
return 0;
}
注意,这样的无个数输入需要最后Ctrl+Z一下,代表输入结束,如果你用了freopen或者是机测就不用在意,反正这样写交NOIP不会错~
然后要说的是,栈会溢出的!如果输入有超过2万的数,基本上是不行了,交上去会……运行错误。
好的,栈也是有专门的容器的,你也可以不用递归:
头文件:stack
声明方式:stack <存储类型> 栈的名字;
如:stack <int> a;
入栈:栈的名字.push(入栈的数);
如:a.push(x); a.push(2);
返回栈顶元素的值(不删除此元素):栈的名字.top();
如:x=a.top();
删除栈顶元素(不返回此元素的值):栈的名字.pop();
如:a.pop();
判断栈是否为空:栈的名字.empty(); 空返回true,反之返回false。
如:if(!a.empty()) return 0;//如果栈为空便结束
返回栈中元素个数:栈的名字.size();
如:len=a.size();
关于栈就这些了,接下来还有队列【吐血】……
好的,接下来是队列了
【队列】最形象的比喻:一个管子,只能从后面进,从前面出。什么意思?就是先进去的先出,后进去的后出,如图。
假如有一列数:1,2,3,4,让我们来模拟一下队列:
①1入队。队列中的数为(从左往右):1;
②2入队。队列中的数为(从左往右):1,2;
③3入队。队列中的数为(从左往右):1,2,3;
④1入队。队列中的数为(从左往右):1,2,3,4;
⑤出队(只有一种操作,因为你只能取出队头元素,不能取出中间的元素):1出队,队列中的数为(从左往右):2,3,4;
⑥出队(只有一种操作,因为你只能取出队头元素,不能取出中间的元素):2出队,队列中的数为(从左往右):3,4;
⑦出队(只有一种操作,因为你只能取出队头元素,不能取出中间的元素):3出队,队列中的数为(从左往右):4;
⑧出队(只有一种操作,因为你只能取出队头元素,不能取出中间的元素):4出队,队列为空。
队列又有什么用呢?首先肯定是广搜啦,然后队列里还有一种极其恶心的优先队列……不想说什么了,其实就是堆而已。至于例子嘛,自己看广搜(我不会告诉你我是用数组模拟队列的)
如果要用标准队列……如下:
头文件:queue
声明方式:queue <存储类型> 队列的名字;
如:queue <int> a;
入栈:队列的名字.push(入栈的数);
如:a.push(x); a.push(2);
返回队头元素的值(不删除此元素):队列的名字.frond();
如:x=a.frond();
删除队头元素(不返回此元素的值):队列的名字.pop();
如:a.pop();
判断队列是否为空:队列的名字.empty(); 空返回true,反之返回false。
如:if(!a.empty()) return 0;//如果队列为空便结束
返回栈中元素个数:栈的名字.size();
如:len=a.size();
如果你以为完了,呵呵,还有,链表!
#--------------------------------------------------------------------------------#
好吧先说到这,有时间再写 By WZY