# 塔子哥の视频带读讲解
算法常识-树&图的读入和存储 (opens new window)
# 前言
只刷过LeetCode的同学在笔试阶段可能对ACM模式感到困惑。特别是对于树,图的读入以及存储。因为在核心代码模式中树的读入和存储都已经处理好了,而ACM模式中是直接让你读入规定格式的数据,然后自己存储。所以塔子哥这里写一篇文章来介绍一下树图的读入和存储。
什么是ACM模式?
需要自己构造输入数据格式,评测平台不会给你任何代码,最后也需要我们自行输出。例如牛客,赛码。
什么是核心代码模式?
功能函数已经给你封装好了,无需处理输入输出。直接返回结果即可。例如LeetCode
# 图的读入与存储
通常来说,图的读入形式有两种
# 1.给出所有边
给定边的个数和点的个数,通常记作 , 接着给出 行,每行两个整数 代表着第条边所连接的两个点。此外,如果这张图带权,则每行就是三个整数,第三个整数是权值。例如题目:
P1224 携程-2023.04.15-春招-第三题-魔法之树 (opens new window)
以这道题为例:
1.读入一般使用语言自带的输入输出库即可。
2.存储通常使用可变长二维数组 :开辟一个长度为的数组,其中每个元素都是一个可变长数组(C++中就是vector , Java中就是List , Python中就是list) 。具体见下方代码
- C++
- Java
- Python
- Go
- JavaScript
// 万能头,包含一切可能涉及到的库。各大平台都提供本头文件!
#include<bits/stdc++.h>
// 图的存储:开一个全局的定长数组,其中每个元素都是一个不定长数组vector<int>
// 开1001 是因为节点下标范围为[1,1000] , 所以需要多开一个
// 你所见到的开1005,1006也是这个原因。至少多开辟一位即可
vector<int> e[1001];
// ...
// 图的读入
int n;
cin >> n;
// 由于是树,所以只需要读n - 1 条边
for (int i = 1 ; i < n ; i++){
int x , y;
cin >> x >> y;
e[x].push_back(y);
// 由于你无法确认x,y之间谁是父亲节点,所以需要存双向边,
// 在dfs的过程中防止返祖即可(返祖会引发死递归!)。
e[y].push_back(x);
// PS:在有一些题目里,他会明确规定谁是父亲,这种情况下就不用存双向边,
// 且在dfs的过程中也不用担心返祖的问题.
}
# 2.给出邻接矩阵
给定点的个数 , 接下来 行,直接给出邻接矩阵 , 代表 之间有一条边, 代表没有边。例如题目:
华为-2022年9月23日-秋招机考-第三题-最省出游方案 (opens new window)
这种题目通常见于图中点的个数有限的情况
这里就不放具体代码了,这种情况我们直接定义二维数组即可。
# 树的读入与存储
1.存储 : 众所周知,树是无向无环图。所以存树和存图没有本质区别。 遇到树的题可以直接用上述方法存储。
2.读入:同时也是由于树的无向无环的性质,树具有一种独特的读入方式,即给出父亲节点数组:
给出 个正整数 ( )表示第 个节点的父亲。规定 号节点是根节点。例如题目:
P1141 美团-2023.04.01-第五题-染色の树 (opens new window)
这样的读入,我们只需要仿造上述方法,循环一遍,将 当作一条单向边往数组里插入即可。