以下总结摘自y总

目录

  • DFS和BFS
  • 树与图的存储
  • 树与图的遍历
  • 拓扑排序
  • 朴素dijkstra算法
  • 堆优化版dijkstra
  • Bellman-Ford算法
  • spfa 算法(队列优化的Bellman-Ford算法)
  • spfa判断图中是否存在负环
  • floyd算法
  • 朴素版prim算法
  • Kruskal算法
  • 染色法判别二分图
  • 匈牙利算法 (二分图匹配)

DFS和BFS

842. 排列数字
843. n-皇后问题
844. 走迷宫
845. 八数码

树与图的存储

树是一种特殊的图,与图的存储方式相同。
对于无向图中的边ab,存储两条有向边a->b, b->a。
因此我们可以只考虑有向图的存储。

(1) 邻接矩阵:g[a][ b ] 存储边a->b

(2) 邻接表:

有向图的邻接表存储就是对于每个点 v 对应一个头节点, 记录在h[v]
idx是图里边的编号,和建图的顺序有关,对于某一个点v, 它的所有邻边的编号不一定是连续的。
e 数组是edge的缩写,记录了某一条有向边的终点
ne数组是next的缩写,记录了邻接表里的同一个点的下一条邻边的idx
ne[idx]=h[a]; h[a]=idx; 就是把新建的边插入队头。(先把新建的边的next指向现在队头的next,然后更新队头的next)
然后再idx++, 给下一次建边使用
// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[N], e[N], ne[N], idx;// 添加一条边a->b
void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}// 初始化
idx = 0;
memset(h, -1, sizeof h);

树与图的遍历

时间复杂度 O(n+m), n 表示点数,m 表示边数
(1) 深度优先遍历 —— 模板题 AcWing 846. 树的重心

int dfs(int u)
{st[u] = true; // st[u] 表示点u已经被遍历过for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (!st[j]) dfs(j);}
}

(2) 宽度优先遍历 —— 模板题 AcWing 847. 图中点的层次

queue<int> q;
st[1] = true; // 表示1号点已经被遍历过
q.push(1);while (q.size())
{int t = q.front();q.pop();for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true; // 表示点j已经被遍历过q.push(j);}}
}

拓扑排序

模板题 AcWing 848. 有向图的拓扑序列
时间复杂度 O(n+m), n 表示点数,m 表示边数

bool topsort()
{int hh = 0, tt = -1;// d[i] 存储点i的入度for (int i = 1; i <= n; i ++ )if (!d[i])q[ ++ tt] = i;while (hh <= tt){int t = q[hh ++ ];for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (-- d[j] == 0)q[ ++ tt] = j;}}// 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。return tt == n - 1;
}

朴素dijkstra算法

模板题 AcWing 849. Dijkstra求最短路 I

时间复杂是 O(n2+m), n表示点数,m 表示边数

int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;for (int i = 0; i < n - 1; i ++ ){int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点for (int j = 1; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;// 用t更新其他点的距离for (int j = 1; j <= n; j ++ )dist[j] = min(dist[j], dist[t] + g[t][j]);st[t] = true;}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

堆优化版dijkstra

模板题 AcWing 850. Dijkstra求最短路 II
时间复杂度 O(mlogn), n 表示点数,m 表示边数

typedef pair<int, int> PII;int n;      // 点的数量
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储所有点到1号点的距离
bool st[N];     // 存储每个点的最短距离是否已确定// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>> heap;heap.push({0, 1});      // first存储距离,second存储节点编号   //因为要找距离源点最近的点,而pair默认先按第一关键字排再按第二关键字排while (heap.size()){auto t = heap.top();heap.pop();int ver = t.second, distance = t.first;if (st[ver]) continue;st[ver] = true;for (int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > distance + w[i])  // w[i] 切记{dist[j] = distance + w[i];heap.push({dist[j], j});}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

Bellman-Ford算法

模板题 AcWing 853. 有边数限制的最短路
时间复杂度 O(nm), n 表示点数,m 表示边数

上图摘自小呆呆大神 :https://www.acwing.com/solution/content/6320/

backup就相当于,我们bfs()四个方向枚举的时候,是用当前点枚举的,
不能走一个方向后,用新的点接着串联枚举。

const int N=510;
const int M=1e4+10;int n, m;       // n表示点数,m表示边数
int dist[N],backup[N];        // dist[x]存储1到x的最短路距离struct Edge     // 边,a表示出点,b表示入点,w表示边的权重
{int a, b, w;
}edges[M];// 求1到n的最短路距离,如果无法从1走到n,则返回-1。
int bellman_ford()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;// 如果第n次迭代仍然会松弛三角不等式,就说明存在一条长度是n+1的最短路径,//由抽屉原理,路径中至少存在两个相同的点,说明图中存在负权回路。for (int i = 0; i < n; i ++ ){memcpy(backup,dist,sizeof dist);for (int j = 0; j < m; j ++ ){int a = edges[j].a, b = edges[j].b, w = edges[j].w;dist[b]=min(dist[b],backup[a]+w);}}if (dist[n] > 0x3f3f3f3f / 2) return -1;return dist[n];
}

spfa 算法(队列优化的Bellman-Ford算法)

模板题 AcWing 851. spfa求最短路
时间复杂度 平均情况下 O(m),最坏情况下 O(nm), n 表示点数,m 表示边数
Bellman_ford算法会遍历所有的边,但是有很多的边遍历了其实没有什么意义,
我们只用遍历那些到源点距离变小的点所连接的边即可,
只有当一个点的前驱结点更新了,该节点才会得到更新;
因此考虑到这一点,我们将创建一个队列每一次加入距离被更新的结点。



上图摘自:
小呆呆:https://www.acwing.com/solution/content/6325/
orzorz: https://www.acwing.com/solution/content/9306/

int n;      // 总点数
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储每个点到1号点的最短距离
bool st[N];     // 存储每个点是否在队列中// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
int spfa()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;queue<int> q;q.push(1);st[1] = true;//标记入队了while (q.size()){auto t = q.front();q.pop();st[t] = false;//标记出队了for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入{q.push(j);st[j] = true;}}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

spfa判断图中是否存在负环

模板题 AcWing 852. spfa判断负环
时间复杂度是 O(nm), n 表示点数,m 表示边数

int n;      // 总点数
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N], cnt[N];        // dist[x]存储1号点到x的最短距离,cnt[x]存储1到x的最短路中经过的点数
bool st[N];     // 存储每个点是否在队列中// 如果存在负环,则返回true,否则返回false。
bool spfa()
{// 不需要初始化dist数组// 原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。queue<int> q;for (int i = 1; i <= n; i ++ ){q.push(i);st[i] = true;}while (q.size()){auto t = q.front();q.pop();st[t] = false;for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];cnt[j] = cnt[t] + 1;if (cnt[j] >= n) return true;       // 如果从1号点到x的最短路中包含至少n个点(不包括自己),则说明存在环if (!st[j]){q.push(j);st[j] = true;}}}}return false;
}

floyd算法

模板题 AcWing 854. Floyd求最短路
时间复杂度是 O(n3), n 表示点数

摘自:小呆呆 https://www.acwing.com/solution/content/6337/

初始化:for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )if (i == j) d[i][j] = 0;else d[i][j] = INF;// 算法结束后,d[a][b]表示a到b的最短距离
void floyd()
{for (int k = 1; k <= n; k ++ )for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

朴素版prim算法

模板题 AcWing 858. Prim算法求最小生成树
时间复杂度是 O(n2+m), n 表示点数,m 表示边数

int n;      // n表示点数
int g[N][N];        // 邻接矩阵,存储所有边
int dist[N];        // 存储其他点到当前最小生成树的距离
bool st[N];     // 存储每个点是否已经在生成树中// 如果图不连通,则返回INF(值是0x3f3f3f3f), 否则返回最小生成树的树边权重之和
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]; //第一次迭代也就是第一个点的距离不用加st[t] = true;for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);}return res;
}

Kruskal算法

模板题 AcWing 859. Kruskal算法求最小生成树
时间复杂度是 O(mlogm), n 表示点数,m 表示边数

int n, m;       // n是点数,m是边数
int p[N];       // 并查集的父节点数组struct Edge     // 存储边
{int a, b, w;bool operator< (const Edge &W)const{return w < W.w;}
}edges[M];int find(int x)     // 并查集核心操作
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}int kruskal()
{sort(edges, edges + m);for (int i = 1; i <= n; i ++ ) p[i] = i;    // 初始化并查集int res = 0, cnt = 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;res += w;cnt ++ ;}}if (cnt < n - 1) return INF;return res;
}

染色法判别二分图

模板题 AcWing 860. 染色法判定二分图
时间复杂度是 O(n+m), n 表示点数,m 表示边数

int n;      // n表示点数
int h[N], e[M], ne[M], idx;     // 邻接表存储图
int color[N];       // 表示每个点的颜色,-1表示未染色,0表示白色,1表示黑色// 参数:u表示当前节点,c表示当前点的颜色
bool dfs(int u, int c)
{color[u] = c;for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (color[j] == -1){if (!dfs(j, !c)) return false; //染色冲突了}else if (color[j] == c) return false;//染色冲突了}return true;
}bool check()
{memset(color, -1, sizeof color);bool flag = true;for (int i = 1; i <= n; i ++ )if (color[i] == -1)if (!dfs(i, 0)){flag = false;break;}return flag;
}

匈牙利算法 (二分图匹配)

模板题 AcWing 861. 二分图的最大匹配
时间复杂度是 O(nm), n 表示点数,m 表示边数

int n1, n2;     // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx;     // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N];       // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N];     // 表示第二个集合中的每个点是否已经被遍历过bool find(int x)
{for (int i = h[x]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true;if (match[j] == 0 || find(match[j])){match[j] = x;return true;}}}return false;
}// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res = 0;
for (int i = 1; i <= n1; i ++ )
{memset(st, false, sizeof st);if (find(i)) res ++ ;
}

第三章 搜索与图论 【完结】相关推荐

  1. 人工智能:第三章 搜索推理技术

    第三章 搜索推理技术 教学内容:本章在上一章知识表示的基础上研究问题求解的方法,是人工智能研究的又一核心问题.内容包括早期搜索推理技术,如图搜索策略和消解原理:以及高级搜索推理技术,如规则演绎系统.产 ...

  2. Acwing《算法基础课》第3章 搜索与图论

    Acwing<算法基础课>第3章 搜索与图论 文章目录 Acwing<算法基础课>第3章 搜索与图论 深度优先遍历DFS 宽度优先搜索BFS 拓扑排序 dijkstra算法 朴 ...

  3. 第二章 搜索 【未完结】

    目录 Flood Fill 1097. 池塘计数[难度: 简单 / 知识点: 基本板子] 1098. 城堡问题 [难度: 一般 / 知识点: 二进制取位] 1106. 山峰和山谷[难度: 中 / 知识 ...

  4. 算法基础知识总结(搜索与图论)

    三.搜索与图论 1.树与图的深度优先遍历 1.基本思想:利用深度优先搜素 2.树与图的存储与时间复杂度: (1)邻接矩阵:O(∣V∣2)O(|V|^2)O(∣V∣2) (2)邻接表:O(∣V∣+∣E∣ ...

  5. 电子科技大学《图论及其应用》复习总结--第三章 图的连通性

    第三章 图的连通性 一.割边.割点和块 (一).割边及其性质 定义1 边e为图G的一条割边,如果 w(G−e)>w(G)w(G-e)>w(G)w(G−e)>w(G) 定理1 边 e ...

  6. 算法竞赛入门经典(第二版)第三章习题

    声明:作者水平有限,只是会基础C语言的小菜,C++还未入门.作者仅根据算法竞赛入门经典(第二版)书上第三章习题所述题意而编写,并未严格按照原题的输入输出编写,代码仅经过个人测试(OJ网站太慢了).代码 ...

  7. 第三章 垃圾收集器与内存分配策略

    第三章 垃圾收集器与内存分配策略 前言: 3.1 概述 3.2 对象已死? 3.2.1 引用计数算法 3.2.2 可达性分析算法 3.2.3 再谈引用,四种引用类型 3.2.4 生存还是死亡 3.3 ...

  8. 计算机应用基础第三章操作步骤,最新江西三校生计算机应用基础模拟操作题集锦(超实用!)...

    第二章 Windows XP 操作系统 ? [2011高考] 将计算机系统时间修改为2011年9月1日10:30.请写出操作步骤. 答:双击系统托盘中时间图标(或双击"控制面板"窗 ...

  9. DOS批处理高级教程:第三章 FOR命令中的变量(转)

    DOS批处理高级教程:第一章 批处理基础 DOS批处理高级教程:第二章 DOS循环for命令详解 DOS批处理高级教程:第三章 for命令中的变量 DOS批处理高级教程:第四章 批处理中的变量 DOS ...

最新文章

  1. 42所双一流大学校长情况简介(2019年)
  2. ElasticSearch大批量数据入库
  3. 这些最常用的Linux命令,每一条都应该学会!
  4. java.lang.Void 解析与使用
  5. boost::hana::values用法的测试程序
  6. file.seek()/tell()-笔记
  7. c++中类型用new和不用new的区别
  8. 递归求二叉树的深度_优雅地用堆栈替代递归实现二叉树的深度优先搜索
  9. 信息学奥赛C++语言:可口可乐
  10. 领域驱动 开源项目_我如何在开源领域找到工作
  11. 升级到 Android Studio 3.0 + Gradle 4.1 遇到的一些坑及解决方案
  12. JavaWeb学习之EL表达式和JSTL标签库
  13. ghost版32位win10系统,win10系统下载地址
  14. 技嘉主板更新版BIOS
  15. symbian 如何在安装时备份sis文件
  16. Arduino最便宜的模拟量采集
  17. 这5种计算机视觉技术,刷新你的世界观
  18. 余杭医保卡指定使用医院和药店
  19. 谷歌浏览器无法翻译此网页,解决方法?(谷歌浏览器无法翻译成中文,谷歌翻译,最新方法)
  20. 2 Resnet系列网络模型改进

热门文章

  1. bzoj3714:[PA2014]Kuglarz
  2. python运维开发常用模块(四)文件对比模块difflib
  3. IOS中UIActionSheet使用方法详解
  4. vba 单元格 一系例操作
  5. nRF52832 中断相关
  6. 蓝牙mesh — 解密蓝牙mesh系列文章汇总
  7. stm32篇--系统初始化
  8. 模型参数优化(三):模拟退火
  9. 以太坊知识教程------智能合约(2)调用 delegatecall call send
  10. 数学建模——评卷问题