简单算法复习

个人认为,信息学竞赛中最难的部分,要数算法的学习和灵活运用了吧。其实算法呢,讲讲概念很好理解,可一道题目中,就千变万化,纯看个人造诣了。本人在这方面比较弱。。。讲的太浅显,或者有什么问题还请不吝赐教。

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);
    }
}

posted @ 2018-11-24 09:52  Zerosking  阅读(...)  评论(... 编辑 收藏