1. 程式人生 > 其它 >設計模式之訪問者模式(Visitor)

設計模式之訪問者模式(Visitor)

題目傳送門

#include <bits/stdc++.h>

using namespace std;
int n, x, y, u, v;
const int N = 110;

//樹的結構體+儲存陣列
struct Node {
    int id;     // 當前結點ID
    int father; // 爸爸
    int left;   // 左結點ID
    int right;  // 右結點ID
    int depth;  // 深度,不用再次dfs去探測
} t[N];

//記錄邊的關係
typedef pair<int, int> PII;
PII a[N];

//是不是使用過
int st[N];

//用來計某一層的結點個數
int bucket[N];

//通過遞迴構建二叉樹
void dfs(int u) {
    //u是老大,找出它的左兒子和右兒子
    for (int i = 1; i < n; i++) {//遍歷所有關係
        if (a[i].first == u && !st[a[i].second]) {
            //標識已使用
            st[a[i].second] = 1;
            //左結點為空,放入左結點
            if (t[u].left == 0) t[u].left = a[i].second;
                //否則放入右結點
            else t[u].right = a[i].second;
            //修改深度標識
            t[a[i].second].depth = t[u].depth + 1;
            t[a[i].second].father = u;
            //遞迴建立子樹
            dfs(a[i].second);
        } else if (a[i].second == u && !st[a[i].first]) {
            st[a[i].first] = 1;
            if (t[u].left == 0) t[u].left = a[i].first;
            else t[u].right = a[i].first;
            t[a[i].first].depth = t[u].depth + 1;
            t[a[i].first].father = u;
            dfs(a[i].first);
        }
    }
}

//最近公共祖先預設是根結點,就是1,英文簡寫:lowestCommonAncestor
int lca(int x, int y) {
    st[x] = 1;                      //把x的節點記錄已走過
    while (t[x].father) {           //遍歷至根節點
        x = t[x].father;            //更新遍歷爸爸
        st[x] = 1;                  //記錄已走過
    }
    //遍歷至x節點已走過的節點,找到最近公共祖先
    while (!st[y])y = t[y].father;
    return y;
}

int main() {
    //二叉樹結點個數
    cin >> n;
    //接下來的n-1行
    for (int i = 1; i < n; i++) {
        //構建二叉樹
        cin >> x >> y;
        //記錄關係
        a[i] = {x, y};
    }
    //通過遞迴建樹,構建二叉樹
    t[1].depth = 1, t[1].id = 1, t[1].father = 0, st[1] = 1;//根結點1
    dfs(1);

    //表示求從結點u到結點v的距離
    cin >> u >> v;

    //二叉樹的深度
    int maxDepth = 0;
    for (int i = 1; i <= n; i++) maxDepth = max(maxDepth, t[i].depth);
    cout << maxDepth << endl;

    //二叉樹的寬度
    int maxWidth = 0;
    for (int i = 1; i <= n; i++) bucket[t[i].depth]++;
    for (int i = 1; i <= n; i++) maxWidth = max(maxWidth, bucket[i]);
    cout << maxWidth << endl;

    //結點u到結點v間距離:結點間距離的定義:由結點向根方向(上行方向)時的邊數×2,與由根向葉結點方向(下行方向)時的邊數之和。
    //這裡有一個最近公共祖先的問題,才能拿到正確答案
    memset(st, 0, sizeof st);
    int r = lca(u, v);
    //按題意輸出
    cout << (t[u].depth - t[r].depth) * 2 + (t[v].depth - t[r].depth) << endl;
    return 0;
}