个人认为,信息学竞赛中最难的部分,要数算法的学习和灵活运用了吧。其实算法呢,讲讲概念很好理解,可一道题目中,就千变万化,纯看个人造诣了。本人在这方面比较弱。。。讲的太浅显,或者有什么问题还请不吝赐教。
1.搜索
好的搜索是一门艺术,是优雅的暴力。
这几天的的模拟赛告诉我一个真理:练好搜索!练好搜索!!练好搜索!!!毕竟我们实力有限是吧。所以说正解不强求,但暴力分怎么也得拿一点啊。
无奈基础太差,优化算法涉猎较少,现在摆出这几天刷的题吧。
求先序排列:大水题(PJ),但是让我对树的先序,中序,后续排列有了一些理解
高手去散步:DFS水题
家族:BFS水题,但是其中对字符串的处理值得学习
NOIP2003传染病控制:树上搜索,自习想想还是比较好理解的
*NOIP2016愤怒的小鸟:搜索策略不再是单纯的枚举,细节方面也有很多注意的地方。
*NOIP2004虫食算:有技巧的搜索
*NOIP2015斗地主:较复杂的搜索,代码量大。
其他OJ上的题,看了一些但是没写了。只能说自己刷题量还是太少了吧。
需要学习的部分:DFS剪枝,迭代加深,双向广搜,启发式搜索。
2.分治
这几天学的东西,大部分的与分治有关。
分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。上面详细讲的树状数组和线段树,其实都是分治思想的体现。
也不多讲,以题目为例吧:
平面内最近点对:好题嗯。大局分治,局部暴力。
最小三角形:和平面内最近点对差不多,是落实的好题。
*BZOJ4985: 评分:二分+DP?思想极其巧妙。
*BZOJ4592:脑洞治疗仪:线段树/珂朵莉树高级题目。
以上分治题目的质量还是非常高的,值得好好咀嚼吸收。
*3.动态规划
已放弃治疗。。。
如果没退役我一定恶补DP!!! QAQ
4.图论
划重点好啦其实就是板子比较多。
1.最短路
Dijkstra算法(堆优化):
priority_queue < pair <int,int> > q; //优先队列(大根堆)修改为小根堆
int dis[N]; //dis数组:dis[i]表示i点到起点s的距离,初始化为无穷大
bool v[N]; //v数组:节点是否被松弛过
void Dijkstra(int s)
{
for(int i=1;i<=n;i++)
dis[i]=2147483647;
dis[s]=0;
q.push(make_pair(dis[s],s)); //初始节点入队
while(q.size())
{
int x=q.top().second;q.pop(); //出队
if(!v[x]) //如果没被松弛过
{
v[x]=1; //记为已松弛
for(int i=head[x];i;i=e[i].nxt) //遍历所有邻边
{
int y=e[i].to;
if(dis[x]+e[i].v<dis[y]) //如果能松弛
{
dis[y]=dis[x]+e[i].v; //更新
q.push(make_pair(-dis[y],y)); //入队
}
}
}
}
}
至于SPFA...求负环还不是很熟。不写了。
*地铁涨价:最短路+动态加边
*2.二分图匹配
学了但不熟。不写。
3.最小生成树
算法实现挺容易的吧。$Kruskal$就是并查集+贪心。
不过关键的一点就是看你能不能将题目转换成最小生成树的题目。就比如上次选拔考试 水滴 那个题,表面上是暴力模拟,实际上可以建图+最小生成树来做。
还有一个题目:洛谷P1550:一点思维就能转化为最小生成树的水题。
4.强连通分量
Tarjan不熟。。。先把板子背了吧。
DFN[ i ] : 在DFS中该节点被搜索的次序(时间戳)
LOW[ i ] : 为i或i的子树能够追溯到的最早的栈中节点的次序号
void tarjan(int i)
{
int j;
dfn[i]=low[i]=++time;
in[i]=1;sta[++top]=i;
for (int e=head[i];e;e=edge[e].next)
{
j=edge[e].to;
if(!dfn[j])
{
tarjan(j);
if (low[j]<low[i])low[i]=low[j];
}
else if (in[j] && dfn[j]<low[i])
low[i]=dfn[j]; //注意细节
}
if (dfn[i]==low[i]) //判断条件
{
Bcnt++;
do
{
j=sta[top--];
in[j]=0;
belong[j]=Bcnt;
}while(j!=i);
}
}
原文地址:https://www.cnblogs.com/Zerosking/p/10011086.html