树与图的关系:图可以分为有向图和无向图,而树是一种特殊的图,即无环连通图,所以树和图的遍历方式可以作统一讨论。在遍历之前,要先进行储存。
储存模板较为简单,如下:
memset(h,-1,sizeof h);
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
与拉链法相似,h数组可以理解为主链,e、ne、idx与单链插入中所用到的作用相同。此函数作用可以理解为将b接在以a所在主链位置的支链上,令a指向b。在进行无向图储存时,只需要add(a,b);add(b,a),使a与b双向指向。
树与图的遍历:
1.深度优先遍历:
主要模板
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);
}
}
st用于记录当前节点的访问状态,循环递归访问每一个节点并记录、处理,每次都从一个节点访问到没有下位节点为止,以达到深度优先遍历。
应用例题:
在这题中,需要在遍历每个节点的时候记录删掉该点后剩余连通块中点数的最大值:
int dfs(int u)
{
st[u]=ture;
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);
ans=min(ans,res);
return sum;
}
-----------------------------------------------------------------------------------------------------------------------------------------------------
2.宽度优先遍历
应用模板:
int bfs()
{
int hh=0,tt=0;
q[0]=1;
memset(d,-1,sizeof d);
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)
{
d[j]=d[t]+1;
q[++tt]=j;
}
}
}
return d[n];
}
其中d数组表示每个点与起点的距离,该函数最终会返回1到n的距离,以宽度优先搜索的方式从1开始一层一层的判断。
对于宽度优先搜索在无环有向图上的应用,可以进行拓扑排序以得到图中的拓扑数:
bool topsort()
{
int hh=0,tt=-1;
for(int i=1;i<=n;i++)
if(!d[i])
q[++tt]=i;
while(hh<=tt)
{
int t=q[hh++];
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
d[j]--;
if(d[j]==0) q[++tt]=j;
}
}
return tt==n-1;
}
树与图的遍历就是对深度优先遍历和宽度优先遍历的应用,主要还是根据题意对模板的修改与活用。