如果题目的空间限制为512MB可以不必考虑这种 优化,直接使用arraylist[]存储邻接表,,但是空间限制很小的情况下,二维存储肯定是会mle的,那么我们可以用多个一维表来存储邻接表
原理
每一条有向边我们都会用cnt来记录是标号
这里我们会创建几个表:
1.head[i]: 用于表示节点i的第一条邻接边
2.next[i]: 表示第i条边之后是哪条边邻接
3.to[i]: 表示第i条边的终点是哪个节点
4.w[i]: 表示第i条边的权重是多少
看到这里可能会觉得很抽象,不急我们先屡屡关系
首先邻接表要看是哪个节点的邻接表,假设 是a节点的,那么a节点的第一条邻接边则是 第head[a]条边(假设值为b)
那么我们要去next中找到第二条邻接边也就是next[b],直到next[b]=0;
而to和w就按照正常情况去记录第cnt条边的终点和权重 ;
举例:
这个图包含以下边:
- 边 (1, 2)
- 边 (1, 3)
- 边 (2, 4)
- 边 (3, 4)
- 边 (3, 5)
- 边 (4, 5)
添加边的过程
- 添加边 (1, 2) :
-
head[1] = 1,表示节点 1 的邻接表从边 1 开始。next[1] = 0,表示边 1 是节点 1 的唯一邻接边。to[1] = 2,表示边 1 的目标节点是 2。
- 添加边 (1, 3) :
-
head[1] = 2,现在节点 1 的邻接表头指向边 2(新的边)。next[2] = 1,表示边 2 的“下一条边”是边 1。to[2] = 3,表示边 2 的目标节点是 3。
- 添加边 (2, 4) :
-
head[2] = 3,表示节点 2 的邻接表从边 3 开始。next[3] = 0,表示边 3 是节点 2 的唯一邻接边。to[3] = 4,表示边 3 的目标节点是 4。
- 添加边 (3, 4) :
-
head[3] = 4,表示节点 3 的邻接表从边 4 开始。next[4] = 0,表示边 4 是节点 3 的唯一邻接边。to[4] = 4,表示边 4 的目标节点是 4。
- 添加边 (3, 5) :
-
head[3] = 5,表示节点 3 的邻接表从边 5 开始。next[5] = 4,表示边 5 的“下一条边”是边 4。to[5] = 5,表示边 5 的目标节点是 5。
- 添加边 (4, 5) :
-
head[4] = 6,表示节点 4 的邻接表从边 6 开始。next[6] = 0,表示边 6 是节点 4 的唯一邻接边。to[6] = 5,表示边 6 的目标节点是 5。
代码实现:
public static int n, m, s, cnt;
// 最大节点数和最大边数,确保足够容纳图的所有数据
public static int MAXN = 100001;
public static int MAXM = 200001;
// 存储图的信息
public static int[] head = new int[MAXN]; // 存储每个节点的邻接表头
public static int[] next = new int[MAXM]; // 存储图中每条边的下一个边
public static int[] to = new int[MAXM]; // 存储边的目标节点
public static int[] quan = new int[MAXM]; // 存储每条边的权重
添加:
// 添加一条边到图中
cnt=1
public static void add(int h, int t, int w) {
next[cnt] = head[h]; // 将原来 h 的邻接表头指向当前边
to[cnt] = t; // 目标节点是 t
quan[cnt] = w; // 边的权重是 w
head[h] = cnt++; // 更新节点 h 的邻接表头为当前边,并递增边的计数器
}
查找:
// 遍历与当前节点 h 相邻的所有节点
for (int nex = head[h]; nex != 0; nex = next[nex]) {
int nextNode = to[nex]; // 邻接节点
int weight = quan[nex]; // 边的权重
}