一个FLAG #06# 二叉树两结点间的最短路径长度

二叉树两个结点之间的最短路径长度。完整题目见参考[1]

#include <cstdio>
#include <cstring>

#define MAXN 20

int pre[MAXN]; // 存每个结点的父结点
int floor[MAXN]; // 存每个结点所在的层数,根结点在第1层
int d[MAXN][MAXN]; // 保存两个结点之间的最短路径长度

int getTheNearestCommonFather(int a, int b); // 找最近的公共祖先结点的id 

int getAns(int a, int b)
{
    if (d[a][b]) return d[a][b];
    
    // 若未计就计算,并保存计算过程中的结果
    
    int f_id = getTheNearestCommonFather(a, b);
     
    if (!d[a][f_id]) {  
        d[a][f_id] = d[f_id][a] = floor[a] - floor[f_id];        
    }
    
    if (!d[f_id][b]) {
        d[f_id][b] = d[b][f_id] = floor[b] - floor[f_id];
    }
    
    d[a][b] = d[b][a] = d[a][f_id] + d[f_id][b];
    
    return d[a][b];       
}

int main()
{
    int T, n, m; // T数据组数 
    // n某组数据的结点数量
    // m某组数据的查询次数    
    
    scanf("%d", &T);
    
    int left, right; // 临时存储某结点的左右子结点 
    int a, b; // 临时存储待查询的两个结点
    while (T--) { 
        scanf("%d %d", &n, &m);
        
        memset(pre, 0, sizeof(pre));        
        memset(floor, 0, sizeof(floor));
        memset(d, 0, sizeof(d));
        
        pre[1] = 1; // 根结点的祖先还是1 该初始化似乎多余 
        floor[1] = 1; // 根结点在第1层
        for (int i = 1; i <= n ; ++i) {
            scanf("%d %d", &left, &right);    
            if (left != -1) {
                pre[left] = i;
                floor[left] = floor[i] + 1;        
            }
            if (right != -1) {
                pre[right] = i;    
                floor[right] = floor[i] + 1;        
                // 如果数据给出顺序不规则,这里的floor初始化会有逻辑错误,需要特别处理。 
            }            
        }

        for (int i = 0; i != m; ++i) {
            scanf("%d %d", &a, &b);
            printf("ans: %d\n", getAns(a, b));
        }        
    } 
    return 0;
}

// 找最近的公共祖先结点的id 
int getTheNearestCommonFather(int a, int b)
{    
    if (a == 1 || b == 1) return 1;
    
    int d; // 保存两结点的层数差 
    // 两结点不在同一层,转化为同一层 
    if (floor[a] > floor[b]) {
        d = floor[a] - floor[b];
        while (d--) a = pre[a];
    } 
    
    if (floor[b] > floor[a]) {
        d = floor[b] - floor[a];
        while (d--) b = pre[b];
    }
    
    // 同一层的结点找最近的公共祖先结点id
    while (a != b) {
        a = pre[a];
        b = pre[b];
    } 
    
    return a;
}

 

例题6-6 小球下落 - 直接模拟最后一个小球下落

#include <cstdio>
#include <cstring>

int main()
{
    int D, I; // D叶子深度 I小球个数
    
    int k;
    while (scanf("%d%d", &D, &I) == 2) {
        k = 1; // 依然用 k 来标识小球的当前位置 
        for (int i = 1; i < D; ++i) {
            if (I % 2 != 0) { // 奇数球往左走 
                k = k * 2; 
                I = (I + 1) / 2; // 相对左树,是第几个球 
            } else { // 偶数球往右走 
                k = k * 2 + 1; 
                I = I / 2; 
            }            
        }

        printf("%d\n", k);
    }   
     
    return 0;
}

 

参考

[1] Problem B 二叉树(2019计算机)_算法,二叉树_Closure-CSDN博客

[2] 并查集详解(超级简单有趣~~就学会了)_短发-CSDN博客

posted @ 2020-03-24 17:11  xkfx  阅读(533)  评论(0编辑  收藏  举报