------------------------------施工中---------------------------
前置知识:递归、DFS、BFS、回溯、栈、队列、树、基础动态规划、链表
(下文中,n 表示图中点的个数,m 表示图中边的个数)
一、图的存储
1、邻接矩阵:
用二维矩阵 {ai,j}(n*n) 表示点 i 与点 j 之间是否有边直接相连以及边的状态。
2、边表:
存储图中的所有边,示例代码中 x 和 y 为边的两个端点,v 为边的状态。
1 struct edge { 2 int x, y, v; 3 } edge[MAX + 10];
邻接矩阵与边表的对比:
邻接矩阵以矩阵的方式将图存储了起来,显然空间复杂度为 O(n2),边表则仅存储图中边的信息,显然空间复杂度为 O(m),因而稀疏图中,边表存储效率更高,稠密图中二者相差不大
1)对于询问图中某两点之间是否有边直接相连,邻接矩阵可以直接检查 ai,j 的具体值,边表则需进行遍历。
显然,邻接矩阵的效率更高
2)对于查找所有与 i 直接相连的点,可以检查 ai,j(j ∈ [1, n],j ≠ 0) 的值,时间复杂度为 O(n),边表仍需遍历,时间复杂度为 O(m)
一般情况下邻接矩阵的效率更高。
为了提高这类问题下边表的效率,将边表中的边改为单向边,引入前向星和邻接表。
3、前向星:
对于边集 E,获取其对应单向边表(x 为起点(第一关键字),y 为终点(第二关键字)),将边表按照第一关键字进行排序,对于某一点 i ,记录其在排序后的边表中,以该点为起点的边所在的边表下标区间 [l, r]。
显然,如果要查找所有与 i 直接相连的点,仅需从 l 遍历至 r 即可。
1 int l[MAXN + 10], r[MAXN + 10]; 2 struct Edge { 3 int x, y; 4 friend bool operator < (const Edge a, const Edge b); 5 } edge_list[MAXM + 10]; 6 7 bool operator < (const Edge a, const Edge b) { 8 return a.x < b.x; 9 } 10 11 void prepare() { 12 std::sort(edge_list + 1, edge_list + 1 + m * 2); 13 l[edge_list[1].x] = 1; r[edge_list[m * 2].x] = m * 2; 14 for (int i = 2; i <= m * 2; ++i) if (edge_list[i].x != edge_list[i - 1].x) { 15 r[edge_list[i - 1].x] = i - 1; 16 l[edge_list[i].x] = i; 17 } 18 }