基本图论

· · 个人记录

1. 图的一些基本概念

2. 有向边和无向边、有向图和无向图

3. 完全图、稀疏图、稠密图

4. 例题:可莉的难题

这题很多人以为要存图,实际上是玩你的。
断开第一个点需要炸掉 n-1 条边
断开第二个点需要炸掉 n-2 条边

\cdots\cdots

最后这道题的答案为 (n-1)+(n-2)+(n-3)+\cdots+(n-k+1)

5. 权值、度

6. 邻接矩阵

7. 邻接表

8. 邻接矩阵和邻接表的优点和缺点

用了一个表来表示:

图的类型 优点 缺点
邻接矩阵 好写、查询时间为 O(1) 浪费空间
邻接表 节省空间 理解较难、查询时间为 O(n)

9. 例题:图的存储、图的存储与出边的顺序

$\text{AC}$ 记录2:[link](https://www.luogu.com.cn/record/119414407) ### 10. 遍历 图上遍历分两种:DFS、BFS,这里都说一下: - DFS 前置芝士:DFS 图上DFS并没有什么特殊的:就是将所有节点可以直接到达的点枚举。注意一下边界即可。 接下类给出模板: ```cpp void dfs(int x) { if(x到达边界) return; for(int i=0;i<a[x].size();i++) { ... dfs(a[x][i]);//遍历 ... } } ``` - BFS 前置芝士:BFS 图上BFS和BFS差不多,先将一些点压入队列,然后每次弹出,将它的相邻节点全部压入队列。 接下来给出模板: ```cpp for(int i=1;i<=n;i++) if(a[i]符合要求) q.push(i); while(!q.empty()) { int u=q.front();q.pop(); if(u到达边界) continue; for(int i=0;i<a[u].size();i++) { ... q.push(u); ... } } ``` ### 11. 图的一些其他术语 - 环 分为自环和环。 自环:自己到自己有一条边 环:一条只有第一个和最后一个顶点重复的非空路径 - 重边 可以理解为两个点之间不只有一条直接路径,这些重复的直接路径为(一组)重边。 - 简单图 不含环与重边的图。 - 反图 可理解为取反所有边方向。(例如本来是 $i\to j$,改成 $j\to i$) ### 12. 有向无环图 有向无环图(Directed Acyclic Graph),简称DAG 定义:是一张有向图,并且没有**环**的一张图。 对一张有向无环图,求最短路算法为 $O(n+m)$。先拓扑排序,再将方程改为 $dis_u=\min(dis_u,dis_v+dis_{v,u})$ 即可。 ### 13. 练习 - 建议 - [高手去散步](https://www.luogu.com.cn/problem/P1294) - [漂浮的鸭子](https://www.luogu.com.cn/problem/P5145) - [图的遍历](https://www.luogu.com.cn/problem/P3916) ### 14. Floyd-多源最短路算法 - 多源最短路模板 [题目传送门](https://www.luogu.com.cn/problem/B3647) Floyd运用的是DP的思想。假设有两个点 $x,y$,我们只有两种走法: 1.直接从 $x$ 点走向 $y$ 点。 那么可以得到方程 `f[x][y]=a[x][y]`。 2.先从 $x$ 点走向 $z$ 点,再从 $z$ 点走向 $y$ 点。 那么可以得到方程 `f[x][y]=f[x][z]+f[z][y]`。 最后取最小值便可,核心代码实现:时间复杂度 $O(n^3)
   for(int k=1;k<=n;k++)
                 for(int i=1;i<=n;i++)
                        for(int j=1;j<=n;j++)
                                f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

15. Dijkstra-单源最短路算法

16. 拓扑排序

拓扑排序例题:B3644
这题一看就是DAG(有向无环图)
我们知道,必定要先列出祖先。祖先的入度一定为 0,不然就还会有祖先先输出。
那么新建一个队列,每一次将入度为 0 的点压入队列。
每弹出一个点,就将他所有可出去的儿子的入度 -1,或者说删除这个点。还要将他压入队列。
队列为空时结束。
时间复杂度:由于顶多经过每个点一次,每条边一次,所以时间复杂度为 O(n+m)
核心代码:

for(int i=1;i<=n;i++) if(r[i]==0) q.push(i);
while(!q.empty())
{
        int u=q.front();q.pop();
        for(int i=0;i<a[u].size();i++)
        {
            int v=a[u][i];
            r[v]--;
            if(r[v]==0) q.push(v);
        }
        ans[++cnt]=u;
}

17. 最小生成树