数据结构学习记录——树(1)

路径:从树上的一点到另外一点所经过的不重合的点和边的集合。

一颗n节点的树有n-1条边。

1.有根树

1.1树的储存方法

vector

vector<int>edges[N+1];
int n, father[N+1];

void addedge[int x, int y]{
    edges[x].push_back(y);
}

//遍历x的所有儿子
int l = edges[x].size();
for (int i = 0;i < l; i++){
    edges[x][i]
    ...
}

for(auto i : edges[x]){
    ...
}//c++11的特性,auto i来遍历所有的edges[x] 

1.2有根树的DFS序

DFS是指深度优先搜索,从一个结点开始,选择一条路径并走到底,并通过回溯来访问所有节点的方法。

有根树的DFS序是指从根节点开始的深度优先搜索过程中一次记录经过的点所生成的序列。

vector<int>dfn;

void Dfs(int x){
    dfn.push_back(x);
    for x 的所有儿子y{
        Dfs(y);
    }
}

Dfs(root);

1.3有根树的BFS序

BFS是指宽度优先搜索,也指层级顺序搜索,我们按深度从小到大的顺序依次遍历所有点。

有根树的BFS序是指从根节点开始的宽度优先搜索过程中依次记录经过的点所生成的序列。

void Bfs(int root){
    将root加入队列q;
    while(q非空){
        x = q队首元素;
        x出队;
        for x 的所有儿子y
            y入队;
    }
}

Bfs(root);

2.无根树

2.1无根树的BFS和DFS

无根树即为没有根结点的树,树中节点只有相邻关系而无父子关系。

遍历无根树时,可以从任意一个节点开始,类似有根树的方式一样去遍历整棵树。唯一的区别是在进入一个新节点时,需要记录这个节点的来源节点,在遍历新节点的相邻节点时,避免重复访问来源节点即可。

void DFS(int from, int x){
    for x 的所有相邻节点y{
        if(y!=from)
            DFS(x,y);
    }
}

DFS(-1, x);

树的直径

树的直径是指书上任意两个节点之间最长(路径的长度一般指的是路径经过的边的数量)的路径。

一棵树可以存在多条直径,他们的长度相等。

树的直径的中间节点被称为树的中心,(图中m节点),如果直径上有偶数个节点,那么中间的两个节点都可以是树的中心。树的中心到其他点的最长路径最短。

*树的直径可以用两次搜索求得。第一次从任意一个节点开始搜索,找出距离最远的节点a。第二次从a节点开始搜寻,找到距离节点a最远的节点b,则a-b即为树的直径。

例题

1.求树上路径

给你一棵 n 个节点的树(节点的编号为 1 到 n)和树上的两个节点 u,v,请求出从 u 到 v的路径上经过的所有节点的编号。

输入格式

第一行一个整数 n表示节点数。

接下来 n−1行,每行两个整数 x,y 表示 x 号节点和 y号节点之间有一条边。

输入保证是一棵树。

接下来一行两个整数 u和 v,表示我们要求的是从 u 号节点到 v号节点的路径上经过的所有节点的编号。

输出格式

输出一行,表示从 u号节点到 v 号节点的路径上经过的所有节点的编号,从 u 开始到 v 结束,节点编号之间用一个空格隔开。

#include<bits/stdc++.h>;

using namespace std;

int n ,pre[100001],c[100001], l;
vector<int>edges[100001];

inline void dfs(int x){
    for(auto y : edges[x]){
        if(y!=pre[x]){
            pre[y] = x;
            dfs(y);
        }    
    }
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i<n ; i++){
        int x, y;
        scanf("%d%d", &x, &y);
        edges[x].push_back(y);
        edges[y].push_back(x);
    }
    int u,v;
    scanf("%d%d", &u, &v);
    pre[u] = -1;
    dfs(u);
    l = 0;
    for(int i = v; i!= u; i = pre[i])
        c[++l] = i;
    c[++l] = u;
    for (int i = l; i; --i)
        printf("%d ", c[i]);
}

2.树的直径

给你一棵 n 个节点的树(节点的编号为 1 到 n),请求出这棵树的直径的长度。

输入格式

第一行一个整数 n表示节点数。

接下来 n−1行,每行两个整数 x,y 表示 x 号节点和 y号节点之间有一条边。

输入保证是一棵树。

输出格式

输出一行一个整数表示直径的长度。

数据规模

对于所有数据,保证 1≤n≤106,1≤x,y≤n。

#include<bits/stdc++.h>;
#include<string.h>;

using namespace std;

int n ,pre[100001], dis[100001];
vector<int>edges[100001];

inline void dfs(int x){
    for(auto y : edges[x]){
        if(y != pre[x]){
            pre[y] = x;
            dis[y] = dis[x] + 1;
            dfs(y);
        }
    }
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i<n ; i++){
        int x, y;
        scanf("%d%d", &x, &y);
        edges[x].push_back(y);
        edges[y].push_back(x);
    }
    memset(dis, 0, sizeof(dis));
    memset(pre, 0, sizeof(pre));

    pre[1] = -1;
    dfs(1);
    int idx = 0, v = 0;
    for(int i = 1; i <= n; i++){
        if(dis[i] > v)
            v = dis[i], idx = i;
    }
    memset(dis, 0, sizeof(dis));
    memset(pre, 0, sizeof(pre));
    pre[idx] = -1;
    dfs(idx);
    v = 0;
    for(int i =1; i <= n; i++)
        v = max(v, dis[i]);
    printf("%d ", v);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值