图论算法伪代码(自己复习用)

1.朴素版的dijkstra()算法(适用于稠密图)O(n^2):

首先把dist都初始化为0x3f3f3f3f,然后1号点dist置0,然后进行n - 1次循环更新剩余的n - 1个点到1号点距离。

循环内容:首先循环找到目前为止dist最小的而且不在集合当中的一个点t,然后用该点更新所有它可以到达的点。最后将点t加入集合。

最后如果n号点的dist距离仍为inf,则到达不了,否则输出dist[n]。邻接矩阵存放图

2.堆优化版的dijkstra()算法(适用于稀疏图)O(mlogn):

我们可以把距离与对应点的信息放到小根堆里面,优化朴素版本寻找min dist的步骤,然后借助队列更新dist数组。邻接表存放图

定义小根堆: priority<PII,vector,greater> heap;

3.bellman_ford()算法(求限制步数的最短路问题) O(nm):

如果步数限制为k,那么就循环k次,然后循环所有边,更新dist数组:dist[b] = min(dist[b], backup[a] + w);记得要用备份数组backup储存上一步的dist,以免发生串联

4.SPFA算法 一般O(m), 最坏O(nm):

对bellman_ford算法做出的优化算法,用队列存放dist更新了的点,宽搜优化。用st数组存放点是否在队列中的状态,当dist更新的话,如果!st[i],则更新st[i] = true;

SPFA求负环:我们把所有点加入队列,然后通过队列维护cnt数组,如果cnt[i] >= n说明存在负环。

5.floyd()算法 (多源汇最短路算法)O(n^3):

首先初始化d[] [],然后三重循环k,i,j,d[i] [j] = min(d[i] [j], d[i] [k] + d[k] [j]);

6.prim()算法 O(n^2):

初始化dist数组为0x3f3f3f3f,然后迭代n次,每次找出不在集合中而且距离集合最短的点,将他加入集合,并用它更新其他点的距离dist。

//模板
int prim()
{
    memset(dist, 0x3f, sizeof dist);
    
    int res = 0;
    
    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        
        if (i && dist[t] == INF) return INF;
        if (i) res += dist[t];
        
        for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
        
        st[t] = true;
    }
    
    return res;
}
7.kruskal()算法 O(mlogm):

按边权重从小到大排序每条边(结构体存储,重载一个小于号),然后从小到大枚举,如果a,b不连通,那么就将他们连起来(并查集)。

//存放边的结构体
struct node
{
    int a, b, w;
    
    bool operator< (const node & W)const
    {
        return w < W.w;
    }
}edges[M];
//并查集模板(加路径压缩)
int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}
//首先初始化并查集
for (int i = 1; i <= n; i ++ ) p[i] = i;
//cnt存放已加入的边的数量,ans为最小生成树权重之和
int cnt = 0, ans = 0;
for (int i = 0; i < m; i ++ )
{
	int a = edges[i].a, b = edges[i].b, w = edges[i].w;
        
    a = find(a), b = find(b);
    if (a != b)
    {
        p[a] = b;
        cnt ++ ;
        ans += w;
     }
}
8.染色法判断二分图 O(n + m):

首先for循环迭代每个点,如果这个点还没有染色,那么就将这个点染色,然后dfs它的所有临点,并且将没有染过色的临点染色成另外一种颜色,如果临点已经染过色了那么判断相邻两点颜色是否一致,一致的话返回false。

//part
bool flag = true;
    for (int i = 1; i <= n; i ++ )
    {
        if (!color[i])
        {
            if (!dfs(i, 1))
            {
                flag = false;
                break;    
            }
        }
    }

//dfs
bool dfs(int u, int c)
{
    color[u] = c;
    
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (!color[j])
        {
            if (!dfs(j, 3 - c)) return false;
        }
        if (color[j] == c) return false;
    }
    return true;
}
9.匈牙利算法 O(mn)实际运行效果很好:

首先邻接表存左边到右边的一条边,因为不需要反向访问,所以不用存右边到左边的边。然后st数组存放每个右边的点在本次是否被访问过(如果没有st数组,假如碰到环了会死循环),match数组存放和右边匹配的左边的点。接着循环左边所有点,如果find(i)可以匹配到,那么答案++。find函数:访问x的所有临边j,如果st[j] == 0即未被访问,那么就访问它,然后看j是否有match,如果有的话看一下是否可以把j的match换一个匹配即find(match[j]),如果可以就换,然后把x与j匹配起来。

匈牙利算法部分重要代码:
bool find(int x)
{
    for (int i = h[x]; ~i; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true;
            if (!match[j] || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }
    
    return false;
}
posted @ 2020-11-19 09:14  sunnyday0725  阅读(590)  评论(0编辑  收藏  举报