可以说该方法的前身是 邻接矩阵和邻接表,但是都有一些差强人意,于是就有大佬研究出了这么个数据结构,我觉得可以理解为 数组模拟链表


[

](https://pintia.cn/problem-sets/994805046380707840/problems/1386335159927652361)

主要结构:

  1. struct E
  2. {
  3. int to,w,next;
  4. }Edge[maxn];
  5. int tot,Head[maxn];

存图-链式前向星 - 图1
邻接表 :
image.png
head就是这一块
image.png

初始化

  1. int main(){
  2. //初始化
  3. memset(Head,-1,sizeof Head);
  4. }

有人习惯用 -1 作为空的标志,有人习惯用 0 ,这里我使用 -1

遍历点的边

遍历从 u 出发能够”一步”到达的点或者说是 边

  1. void traversal(int u){
  2. //遍历从 u 出发能够"一步"到达的点或者说是 边
  3. for(int i = Head[u];~i;i=Edge[i].next){
  4. int v = Edge[i].to,w=Edge[i].w;
  5. //do something
  6. }
  7. }

新添加一条新的边

  1. void addEdge(int u,int v,int w){
  2. //第 tot 条边的u->v,长度为 w
  3. Edge[tot].to = v;
  4. Edge[tot].w = w;
  5. //让之前 u 作为起点的最新添加的一条边 作为 第 tot 条边的下一条边,使其序号记为第 tot 条边的 next
  6. Edge[tot].next = Head[u];
  7. //更新,现在 u 作为起点的 最新添加的一条边 的序号 更新为 tot;tot++,为下一次添加边做准备
  8. Head[u] = tot++;
  9. }

head[1] 就是 1 这个点后面的 最新添加的一条边的序号插入一条新边时可以理解为 头插法
image.png
注意:

  • 红色部分其实是不存在的的,只有边的序号(tot)、点的 head 、边的 next,使各条边联系在一起
  • tot :边的序号,全局的,每次新增一条边之后都有 tot++ ,为新增下一条新边做准备。

总结

链式前向星其实就是一个 简化版的 好写一些的 易用的 邻接表

题目

L2-038病毒溯源 :存图 | dfs

  1. #include <iostream>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. const int N = 10010,M = 10010;
  6. int n;
  7. //结构体拆为三个数组了,因为没有权,也就没有w
  8. int h[N], // 对于每个点k,开一个单链表,存储所有k可以走到的点。h[k]存储这个单链表的头结点
  9. e[M], //e[idx] : 第idx条边的终点
  10. ne[M], //ne[idx] : 以第idx边的起点作为起点 的 下一条边
  11. idx=0;
  12. int son[N];//每个点的儿子
  13. bool st[N];
  14. void add(int a,int b){
  15. e[idx] = b,ne[idx] = h[a],h[a] = idx++;
  16. }
  17. int dfs(int u){
  18. int res = 0;//当前往下走的最长路径
  19. son[u] = -1;
  20. for(int i = h[u];i!= -1;i = ne[i]){
  21. int j = e[i];
  22. int d = dfs(j);
  23. if(res < d) res = d,son[u] = j;
  24. else if(res == d) son[u] = min(son[u],j);
  25. }
  26. return res + 1;
  27. }
  28. int main(){
  29. memset(h,-1,sizeof(h));//设置邻接表的表头
  30. scanf("%d",&n);
  31. for(int i = 0; i < n; i++){
  32. int cnt;
  33. scanf("%d",&cnt);
  34. while(cnt--){
  35. int x;
  36. scanf("%d",&x);
  37. add(i,x);//连接一条从i到x的边
  38. st[x] = true;//x有父节点
  39. }
  40. }
  41. int root = 0;
  42. while(st[root]) root++;//找父节点
  43. printf("%d\n",dfs(root));
  44. printf("%d",root);
  45. while(son[root] != -1){
  46. root = son[root];
  47. printf(" %d",root);
  48. }
  49. return 0;
  50. }