1、时间戳:
按照dfs的过程,将每个节点第一次被访问的顺序(v[x]被标记为1时),依次给这n个节点标记1~n的数字即该节点的时间戳。
代码:
1 void dfs(int x){ 2 v[x]=1;dfn[x]=++cnt; //dfn时间戳,cnt初始为0 3 for(int i=head[x];i;i=next[i]){ 4 int y=ver[i]; 5 if(v[y])continue; 6 dfs(y); 7 } 8 }
2、树的dfs序
第一次访问到某个节点时,记录其一次编号,回溯时再记录一次它的编号,最后产生2n的节点序列就是树的dfs序。
性质:某节点x从第一次被标记在节点序列中到第二次被标记之间的节点序列就是以x为根节点的子树的dfs序
代码:
1 void dfs(int x){ 2 a[++m]=x; //a数组存储dfs序 3 v[x]=1; //记录点是否被访问过 4 for(int i=head[x];i;i=next[i]){ 5 int y=ver[i]; 6 if(v[y])continue; 7 dfs(y); 8 } 9 a[++m]=x; 10 }
3、树的深度
树中各个节点的深度是自上而下的统计信息,其中根节点深度为0,其它节点深度即到根节点的层数。往下的子节点深度依次+1,即若当前所在节点x的深度为dep[x],则它的子节点y的深度为dep[y]=dep[x]+1;
代码:
1 void dfs(int x){ 2 v[x]=1; 3 for(int i=head[x];i;i=next[i]){ 4 int y=ver[i]; 5 if(v[y])continue; 6 d[y]=d[x]+1; //父节点向子节点更新深度 7 dfs(y); 8 } 9 }
4、树的子树大小和重心
树的子树大小是自下而上统计的信息,子树大小即以某个节点x为根节点的子树的节点个数,一般用size[x]表示。容易想到,若x的子节点为:y1、y2……yn,则size[x]=size[y1]+size[y2]+…+size[yn];
树的重心。指的是对于一个节点x,从树中删去它,产生的若干个不想连的部分中节点数最多的一颗树的节点数size记为maxn,令maxn取最小值的节点x即一颗树的重心。
代码:
void dfs(int x){ v[x]=1;size[x]=1; //size存储子树大小 int max_part=0; //删除x节点后最大子树的大小 for(int i=head[x];i;i=next[i]){ int y=ver[i]; if(v[y])continue; dfs(y); size[x]+=size[y]; max_part=max(max_part,size[y]); } max_part=max(max_part,n-size[x]); //n为整棵子树节点总数 if(max_part<ans){ans=max_part;pos=x;} //ans记录重心对应的max_part,pos记录重心 }
5、图的连通块的个数和划分
dfs可以求出森林(即多棵不连通的树)中树的个数,并将节点划分到每棵树中。思路就是不停对没有划分的节点x进行dfs遍历,就会访问所有与x连通的点并对它们划分,直到所有点均被划分为止。
代码:
1 void dfs(int x){ 2 v[x]=cnt; 3 for(int i=head[x];i;i=next[i]){ 4 int y=ver[i]; 5 if(v[y])continue; 6 dfs(y); 7 } 8 } 9 int main() 10 { 11 for(int i=1;i<=n;i++) 12 if(!v[i]){cnt++,dfs(i);} //cnt即连通块个数 13 }
原文地址:https://www.cnblogs.com/five20/p/8530924.html
时间: 2025-01-12 03:48:45