【题解】对称二叉树

数的同构

给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。

图一

图二

一般情况(树hash):
https://blog.csdn.net/dpppbr/article/details/52915576

递归判断(用于二叉树):
https://www.cnblogs.com/jingjing1234/p/10822040.html

回归本题

其实就是多考虑了一下节点的顺序问题而已。

法一.
枚举根节点,递归判断是否对称。 O ( n l o g n ) O(nlogn) Onlogn,n是枚举,logn是check函数。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;

int n, cost[N], l[N], r[N], con[N], root, ans;
bool vis[N];



void dfs(int x) {
    if (!x)
        return;
    dfs(l[x]), dfs(r[x]);
    con[x] = con[l[x]] + con[r[x]] + 1;
}

bool check(int x, int y) {
    if (!x && !y)
        return 1;
    if (!x || !y)
        return 0;
    if (cost[x] != cost[y])
        return 0;
    if (check(l[x], r[y]) && check(r[x], l[y]))
        return 1;
}

int main() {
    // freopen("tree.in","r",stdin);
    // freopen("tree.out","w",stdout);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &cost[i]);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &l[i], &r[i]);
        if (l[i] == -1)
            l[i] = 0;
        if (r[i] == -1)
            r[i] = 0;
        vis[l[i]] = vis[r[i]] = 1;
    }
    for (int i = 1; i <= n; i++)
        if (!vis[i]) {
            root = i;
            break;
        }
    dfs(root);
    for (int i = 1; i <= n; i++)
        if (check(l[i], r[i]))
            ans = max(ans, con[i]);
    printf("%d", ans);
}

法二.
显然可以直接hash树的形态,即分中序遍历1(先进左子树)和中序遍历2(先进右子树)记录hash值,对于每一个节点,若是此节点的左儿子的中序遍历1的hash值等于右儿子的中续遍历2的hash值,说明这个点为根的树是对称的。

由于要考虑顺序,所以这里直接乘系数,不平方。

h a s h [ x ] = h a s h [ l [ x ] ] ∗ V 1 + c o s t [ x ] ∗ V 2 + h a s h [ r [ x ] ] ∗ V 3 ; hash[x]=hash[l[x]]*V1+cost[x]*V2+hash[r[x]]*V3; hash[x]=hash[l[x]]V1+cost[x]V2+hash[r[x]]V3;
H a s h [ x ] = H a s h [ r [ x ] ] ∗ V 1 + c o s t [ x ] ∗ V 2 + H a s h [ l [ x ] ] ∗ V 3 ; Hash[x]=Hash[r[x]]*V1+cost[x]*V2+Hash[l[x]]*V3; Hash[x]=Hash[r[x]]V1+cost[x]V2+Hash[l[x]]V3;

实测88pts,运气好的话,像下面这个代码,可以ac。这个方法不建议用。

其实我也没打出来

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
#define llg long long
#define maxn 1000100
#define V1 (llg)(999999751)
#define V2 (llg)(299999827)
#define V3 (llg)(100000007)
#define md (llg)(89999794200117649)
#define mdd (llg)(999999786000011449)
#define yyj(a) freopen(a ".in", "r", stdin), freopen(a ".out", "w", stdout);

inline llg getint() {
    llg w = 0, q = 0;
    char c = getchar();
    while ((c < '0' || c > '9') && c != '-') c = getchar();
    if (c == '-')
        q = 1, c = getchar();
    while (c >= '0' && c <= '9') w = w * 10 + c - '0', c = getchar();
    return q ? -w : w;
}

unsigned long long hal[maxn], har[maxn], Har[maxn], Hal[maxn];
llg val[maxn], n, ans, he[maxn], lson[maxn], rson[maxn];

void dfs(llg x, llg fa) {
    if (lson[x])
        dfs(lson[x], x);
    if (rson[x])
        dfs(rson[x], x);
    he[x] = he[lson[x]] + he[rson[x]] + 1;
    if (he[lson[x]] == he[rson[x]] && hal[lson[x]] == har[rson[x]] && Hal[lson[x]] == Har[rson[x]]) {
        ans = max(ans, he[x]);
    }
    hal[x] = hal[lson[x]] * V1 + val[x] * V2 + hal[rson[x]] * V3;
    Hal[x] = Hal[lson[x]] * V1 + val[x] * V2 + Hal[rson[x]] * V3;
    hal[x] %= md;
    Hal[x] %= mdd;
    har[x] = har[rson[x]] * V1 + val[x] * V2 + har[lson[x]] * V3;
    Har[x] = Har[rson[x]] * V1 + val[x] * V2 + Har[lson[x]] * V3;
    har[x] %= md;
    Har[x] %= mdd;
}

int main() {
    // yyj("D");
    cin >> n;
    for (llg i = 1; i <= n; i++) val[i] = getint();
    for (llg i = 1; i <= n; i++) {
        llg x = getint(), y = getint();
        if (x != -1)
            lson[i] = x;
        if (y != -1)
            rson[i] = y;
    }
    dfs(1, -1);
    cout << ans;
    return 0;
}
posted @ 2020-08-25 21:49  仰望星空的蚂蚁  阅读(13)  评论(0)    收藏  举报  来源