算法常用模板

包含一些常用的算法模板。

数据结构:

Kahn拓扑排序

void TopSort(graph)
{
    for(each point V in the graph)
    {
        if(Indegree[V] == 0)  //这里把所有入度为0的顶点入队
            Enqueue(V, Q);
    }
 
    while(!IsEmpty(Q))
    {
        V = Dequeue(Q);    
        输出(V); //输出V
        cnt++;   //记录输出的顶点的个数,用于判断图中是否有回路
 
        for(each adjacent vertex W of V)  //把V的所有邻接点的入度都减1
        {
            if(--Indegree[W] == 0)
                Enqueue(W, Q);
        }
    }
 
    if(cnt != number of vertices in the graph)  //判断输出顶点的个数(即入度为0的顶点个数)是否与图中的顶点数量相等,如果不相等,则说明图中有回路
        Error("The graph contains a cycle");
}

Tarjan寻找强连通分量

void tarjan(point u)
{
    dfn[u] = low[u] = ++Index//这里深度需要初始化为1
    stack.push(u)//入栈
    for(each (u, v) in E)//遍历邻接点
    {
        if (v is not visted)//没有被访问过
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(v in stack)//在栈里
        {
            low[u] = min(low[u], dfn[v]);
        }

    }
    if (dfn[u] == low[u])//出栈到u
    {
        do
        {
            v = stack.pop;
            print v;
        }while(u == v)
    }
}

Dijkstra最短路径

void Dijkstra(graph)
{
    dis[all] = INT64_MAX;//所有值初始化为最大值
    dis[begin] = 0;//起点初始化为0
    check[all] = 0;//记录节点是否被遍历
    while(check[all] != 1)
    {
        point(check[point] == 0 && dis[point] == min);//没有遍历过且最小
        for(each (point,v) in grap)
        {
            dis[v] = min(dis[v],dis[point] + (point,v));
        }
        check[point] = 1;
    }
}

Floyd最短路径

void Floyd(邻接矩阵)
{
    //循环处理
    for(int i = 0;i < 节点数;++i)
    {
        for(int j = 0;j < 节点数;++j)
        {
            for(int k = 0;k < 节点数;++k)
            {
                if(grap[j][k] > grap[j][i] + grap[i][k])
                {
                    grap[j][k] = grap[j][i] + grap[i][k];
                }
            }
        }
    }
    //去除自最短路径
    for(int i = 0;i < date.size();++i) grap[i][i] = 0;
}

Bellman最短路径

void Bellman(int l[],int r[],int v[])
{
    //l记录边的左节点
    //r记录边的右节点
    //v记录边的权值
    dis[all] = INT64_MAX;
    for(int k = 1;k < 顶点数-1;++k)//节点数-1次
    {
        for(int i = 1;i <= 边数;++i)
        {
            if(dis[r[i]] > dis[l[i]] + v[i]) dis[r[i]] = dis[l[i]] + v[i];
        }
    }
}

SPFA最短路径

void SPFA(graph)
{
    dis[all] = INT64_MAX;
    dis[begin] = 0;
    queue.push(begin)
    while(!queue.empty())
    {
        point = queue.front();//记录头节点并出队
        queue.pop_front();
        for(each (point,v) in graph)//遍历所有point的邻接点v
        {
            if(dis[v] > dis[v] + (point,v))
            {
                dis[v] = dis[v] + (point,v);
                if(v not in queue)//如果在队列中就不用入队
                {
                    queue.push(v)
                }
            }
        }
    }
}

prim最小生成树

void prim(graph)
{
    check[all] = 0;
    check[begin] = 1;
    while(check[all] != 1)
    {
        point(距离生成树最近的节点)
        check[point] = 1;
    }
}//check的路径就是最小生成树

kruskal最小生成树

int find_father(int e)
{
    while(e != father[e]) e = father[e];
    return e;
}

void kruskal(graph)
{
    mulitmap<value,(x,y)> graph;//按权值对边排序
    //查并集
    for(auto elem : graph)
    {
        //判断是否构成闭环
        if(find_father(x) == find_father(y))
        {
            continue;
        }
        //添加边
        father[find_father(y)] = x[0];//直接将y的父亲的父亲设置为 x
    }
}//添加边的路径就是最小生成树

动态规划:

01背包

int back01()
{
    dp[all] = 0;
    weight[all] = 0;
    value[all] = 0;
    for(int i = 0;i < 物品数量;++i)
    {
        for(int j = 背包容量; j >= weight[i];--j)//01背包是从大到小遍历
        {
            dp[j] = max(dp[j], dp[j-weight[i]] + value[i]);
        }
    }
}

完全背包

int back_complete()
{
    dp[all] = 0;
    weight[all] = 0;
    value[all] = 0;
    for(int i = 0;i < 物品数量;++i)
    {
        for(int j = weight[i];j <= 背包容量;++j)//完全背包是从小到大遍历
        {
            dp[j] = max(dp[j],dp[j-weight[i]] + value[i]);
        }

    }
}

多重背包 

void back_multiple()
{
    dp[all] = 0;
    weight[all] = 0;
    value[all] = 0;
    for(int i = 0;i < 物品数量;++i)
    {
        for(int j = 背包容量; j >= weight[i];--j)
        {
            for(int k = 1;k <= i的数量 && k * weight[i] <= 背包容量;++k)//直接遍历数量即可
            {
                dp[j] = max(dp[j], dp[j - weight[i] * k] + value[i] * k);
            }
                
        }
    }
}

字符串:

KMP字符匹配

//如果s[i] == s[j] (或者j == 0)那么就next[i] = j,并++i,++j
//如果s[i] != s[j]那么就j = next[j]
void get_next(string s, int *next)
{
    int i = 1,j = 0;
    next[0] = 0;
    while(i < s.size())
    {
        if(j == 0 || s[i] == s[j]) next[++i] = ++j;
        else j = next[j];
    }
}

int KMP(string s1,string s2,int *next)
{
    int i = 0,j = 0;
    for(;i < s1.size() && j < s2.size();++j,++i)
    {
        if(s1[i] != s2[j])
        {
            //防止j-1越界
            if(j != 0) j = next[j-1];
            else j = 0;
        }
    }
    if(j == s2.size()) return i-j;
    else return -1;
}

Manacher求回文串

string change(string s)
{
    string res = "@#";
    for(char c : s){res += c; res += "#";}
    res += "$";
    return res;
}

void Manacher(string s,int *p)//*p存储节点位置最大半径
{
    int R = 0,Mid = 0;//最右侧和边界中心
    for(int i = 0;i < s.size();++i)
    {
        p[i] = R > i ? min(p[2 * Mid - i],R-i) : 1;//给p[i]赋初值 p[2 * Mid - i] 和 p[i] 在 Mid 对称
        while(s[p[i] + i] == s[i - p[i]]) ++p[i];//向两端拓展直到最大
        if(p[i] + i > R)//迭代R和Mid
        {
            Mid = i;
            R = i + p[i];
        }
    }
}

//朴素算法
void Manacher_1(string s,int *p)
{
    for(int i = 0;i < s.size();++i)
    {
        p[i] = 1;//给p[i]赋初值
        while(s[p[i] + i] == s[i - p[i]]) ++p[i];//向两端拓展直到最大
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值