算法杂记

2019-07-07   


二叉树

普通二叉树

后缀表达式

给定一个二叉表达式树,请你输出相应的后缀表达式,由于有单独的负号,添加括号表示优先级。AcWing4274
输入格式
第一行包含整数 N,1N20N,1\leq N\leq 20,表示节点数量。节点编号 1N1∼N

接下来 NN 行,每行给出一个节点的信息(第 ii 行对应第 ii 个节点),格式为:data left_child right_child

其中,data 是一个不超过 1010 个字符的字符串,left_childright_child 分别是该节点的左右子节点的编号。没有子节点(即 NULL)用 1-1 表示。
输出格式
在一行中输出答案,表达式符号之间不得有空格。
样例:
表达式例子

输入样例:

8
* 8 7
a -1 -1
* 4 1
+ 2 5
b -1 -1
d -1 -1
- -1 6
c -1 -1

输出样例:

(((a)(b)+)((c)(-(d))*)*)

代码:

#include <iostream>
using namespace std;
const int N = 25;

int n;
string v[N];
int l[N], r[N];
int has_father[N];

void dfs(int u){
    cout << '(';
    if(l[u] != -1 && r[u] != -1){// 左右儿子都有,后序遍历
        dfs(l[u]);
        dfs(r[u]);
        cout << v[u];
    }else if(l[u] == -1 && r[u] == -1) cout << v[u];
    else if(l[u] == -1 && r[u] != -1){//只有右儿子说明是负号
        cout << v[u];
        dfs(r[u]);
    }
    cout << ')';
}

int main(){
    cin >> n;
    for (int i = 1; i <= n; i ++ ){
        cin >> v[i] >> l[i] >> r[i];
        if (l[i] != -1) has_father[l[i]] = 1;
        if (r[i] != -1) has_father[r[i]] = 1;
    }

    int root;
    for (int i = 1; i <= n; i ++ ) if (!has_father[i]) root = i;

    dfs(root);
    return 0;
}

中缀表达式:AcWing1623

#include <iostream>
using namespace std;
const int N = 25;

int n;
string v[N];
int l[N], r[N];
int has_father[N];

string res;
void dfs(int u){
    if(u == -1) return;
    if(l[u] == -1 && r[u] == -1) res += v[u];
    else{
        res += '(';
        dfs(l[u]);
        res += v[u];
        dfs(r[u]);
        res += ')';
    }
}

int main(){
    cin >> n;
    for(int i = 1; i <= n; i ++){
        cin >> v[i] >> l[i] >> r[i];
        if(l[i] != -1) has_father[l[i]] = 1;
        if(r[i] != -1) has_father[r[i]] = 1;
    }
    int root;
    for(int i = 1; i <= n; i ++) if(!has_father[i]) root = i;
    dfs(root);
    if(res.size() == 1) cout << res;
    else cout << res.substr(1, res.size() - 2) << endl;
}

完全二叉树的最近公共祖先

编号从1开始的完全二叉树。AcWing3432

     1
    / \
   2   3
  / \ / \
 4  5 6  7
/\ /\ /\ /\
...     ... 

代码:

#include <iostream>
using namespace std;

int main(){
    int x, y; cin >> x >> y;
    while(x != y){
        if(x > y) x /= 2;
        else y /= 2;
    }
    cout << x << endl;
    return 0;
}

二叉树最近公共祖先

AcWing3555

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1010;
int l[N], r[N], p[N];
int d[N];

void dfs(int u, int dist){
    d[u] = dist;
    if(l[u] != -1) dfs(l[u], dist + 1);
    if(r[u] != -1) dfs(r[u], dist + 1);
}

int lca(int a, int b){
    if(d[a] < d[b]) return lca(b, a);
    while(d[a] > d[b]) a = p[a];
    while(a != b) a = p[a], b = p[b];
    return a;
}

int main(){
    int t; cin >> t;
    while(t --){
        int n, m; cin >> n >> m;
        for(int i = 1; i <= n; i ++) {
            int left, right; cin >> left >> right;
            l[i] = left, r[i] = right;
            if(left != -1) p[left] = i;
            if(right != -1) p[right] = i;
        }
        int root = 1;
        while(p[root] != 0) root = p[root];
        dfs(root, 0);
        for(int i = 1; i <= m; i ++){
            int a, b; cin >> a >> b;
            int c = lca(a, b);
            cout << d[a] + d[b] - 2 * d[c] << endl;
        }
    }
}

根能抵达的点的数量

AcWing3712

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 20010, M = N * 2;
int h[N], e[M], w[M], ne[M], idx;
int n, m;

void add(int a, int b, int c){
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

int dfs(int u, int mid, int fa){
    int res = 1;
    for (int i = h[u]; ~i; i = ne[i]){
        int j = e[i];
        if (j == fa || w[i] < mid) continue;// 不能再访问父节点保证了遍历不会重复
        res += dfs(j, mid, u);
    }
    return res;
}

int main(){
    int T; cin >> T;
    while (T -- ){
        scanf("%d%d", &n, &m);
        memset(h, -1, sizeof h);
        idx = 0;
        for (int i = 0; i < n - 1; i ++ ){
            int a, b, c; cin >> a >> b >> c;
            add(a, b, c);
            add(b, a, c);
        }

        int l = 0, r = 1e8;
        while (l < r){
            int mid = (l + r) >> 1;
            if (dfs(0, mid, -1) <= m) r = mid;
            else l = mid + 1;
        }
        cout << r << endl;
    }
    return 0;
}

前序中序求后序

#include <iostream>
using namespace std;
void dfs(string pre, string in){
    if(pre.empty()) return;
    char root = pre[0];
    int k = in.find(root);
    dfs(pre.substr(1, k), in.substr(0, k));
    dfs(pre.substr(k + 1), in.substr(k + 1));
    cout << root;
}
int main(){
    string pre, in;
    while(cin >> pre >> in){
        dfs(pre, in);
        cout << endl;
    }
}

Q.E.D.


我是星,利剑开刃寒光锋芒的银星,绝不消隐