树与图的存储
树是一种特殊的图(无向连通图),与图的存储方式相同。
对于无向图中的边ab,我们需要存储两条有向边a->b, b->a。
因此我们可以只考虑有向图的存储。
邻接矩阵
g[a][b] 存储边a->b,当a,b两点之间有边时,g[a][b] = 1,如果该图是一个带权图,那么g数组中存的就是边上的权值。
邻接表
对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点。(类似哈希表的拉链存储法)
int h[N], e[N], ne[N], idx;
//插入一条边a→b 头插法
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
// 初始化
idx = 0;
memset(h, -1, sizeof h);
树与图的遍历
DFS
bool st[N]; //标记是否走过
//深度优先遍历
void dfs(int u)
{
st[u] = true; //标记一下,已经被搜过了
for(int i = h[u]; i != -1; i = ne[i]) //遍历所有初边
{
int j = e[i]; //当前链表中节点对应图中点的编号
if(!st[j]) dfs(j);
}
}
int main()
{
// 初始化
idx = 0;
memset(h, -1, sizeof h);
return 0;
}
BFS
第一个点入队
while(queue 不空)
{
t = 队头;
拓展t所有邻点;
if(x未遍历)
x 入队
d[x] = d[t] + 1;
}
int st[N];
queue<int> q;
st[1] = true;
q.push(1);
while(q.size())
{
int t = q.front();
q.pop();
for(int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if(!st[j])
{
st[j] = true;
q.push(j);
}
}
}
DFS典例——AcWing 846.树的重心
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10, M = 2*N;
int n;
int h[N],e[M],ne[M],idx;
int ans = N;
bool st[N];
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
int dfs(int u)
{
st[u] = true;
int sum = 1,res = 0;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(!st[j])
{
int s = dfs(j); //当前节点的子树
res = max(res,s);
sum += s; //以当前节点为根节点的子树
}
}
res = max(res,n - sum); //n-sum 为删去以当前节点为根节点的子树后 剩余的节点数
ans = min(ans,res);
return sum;
}
int main()
{
cin >> n;
memset(h,-1,sizeof h);
int a,b;
for(int i = 0; i < n-1 ; i ++ )
{
cin >> a >> b;
add(a,b), add(b,a); //无向图
}
dfs(1); //dfs从哪个节点开始都可以
cout << ans << endl;
return 0;
}
BFS典例——AcWing 847.图中点的层次
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
int n,m;
int h[N],e[N],ne[N],idx;
int q[N]; //队列
int d[N]; //从起点到该点的距离
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}
int bfs()
{
int hh = 0, tt = 0;
q[0] = 1;
memset(d,-1,sizeof d); //初始化为-1 表示 没走过
d[1] = 0;
while(hh <= tt)
{
int t = q[hh ++ ];
for(int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if(d[j] == -1)
{
q[++ tt] = j;
d[j] = d[t] + 1;
}
}
}
return d[n]; //从起点到n的距离
}
int main()
{
cin >> n >> m;
int a,b;
memset(h,-1,sizeof h);
for(int i = 0; i < m; i ++ )
{
cin >> a >> b;
add(a,b);
}
cout << bfs() << endl;
return 0;
}