包含一些常用的算法模板。
数据结构:
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];//向两端拓展直到最大
}
}