文章目录
- 题目传送门
- 算法解析
- 总代码
- 提交记录
- 尾声
题目传送门
洛谷 P5018 [NOIP2018 普及组] 对称二叉树
算法解析
本题 DFS + 剪枝可过!!!
输入左儿子右儿子时如果遇到 − 1 -1 −1 就把它设为 0 0 0,这样好判断。
输入函数:
void inp() {scanf("%d", &n);for(int i = 1; i <= n; ++i)scanf("%d", &w[i]);for(int i = 1; i <= n; ++i) {scanf("%d%d", &le[i], &rt[i]);if(le[i] == -1)le[i] = 0;if(rt[i] == -1)rt[i] = 0;}
}
然后计算出所有子树的结点个数,方便剪枝和跟新答案:
void dfs1(int u) {if(!u)return;dfs1(le[u]);dfs1(rt[u]);cnt[u] = cnt[le[u]] + cnt[rt[u]] + 1;
}
然后就是计算答案了,我们先写一个函数 bool check(int u, int v)
,就是判断以 u u u 结点为根结点的子树和以 v v v 结点为根结点的子树是否对称,这里有很多剪枝,但都很简单,相信大家都能看懂:
void bemax(int &a, int b) {a = a > b ? a : b;
}bool check(int u, int v) {if(!u && !v)return true;if(!u || !v)return false;if(w[u] != w[v])return false;if(cnt[u] != cnt[v])return false;return check(le[u], rt[v]) & check(rt[u], le[v]);
}
有了这个函数,就很好计算答案了:
void dfs2(int u) {if(!u)return;if(check(le[u], rt[u]))bemax(ans, cnt[u]);dfs2(le[u]);dfs2(rt[u]);
}
最后再输出一下 a n s ans ans 就可以了,这样我们就 A(shui)掉了此题。
总代码
#include <cstdio>
using namespace std;const int N = 1e6 + 5;int n;
int w[N];
int le[N], rt[N];
int cnt[N];
int ans;void bemax(int &a, int b) {a = a > b ? a : b;
}bool check(int u, int v) {if(!u && !v)return true;if(!u || !v)return false;if(w[u] != w[v])return false;if(cnt[u] != cnt[v])return false;return check(le[u], rt[v]) & check(rt[u], le[v]);
}void dfs1(int u) {if(!u)return;dfs1(le[u]);dfs1(rt[u]);cnt[u] = cnt[le[u]] + cnt[rt[u]] + 1;
}void dfs2(int u) {if(!u)return;if(check(le[u], rt[u]))bemax(ans, cnt[u]);dfs2(le[u]);dfs2(rt[u]);
}void inp() {scanf("%d", &n);for(int i = 1; i <= n; ++i)scanf("%d", &w[i]);for(int i = 1; i <= n; ++i) {scanf("%d%d", &le[i], &rt[i]);if(le[i] == -1)le[i] = 0;if(rt[i] == -1)rt[i] = 0;}
}void work() {dfs1(1);dfs2(1);printf("%d\n", ans);
}int main() {inp();work();return 0;
}
提交记录
AC 记录
尾声
如果这篇博客对您(您的团队)有帮助的话,就帮忙点个赞,加个关注!
最后,祝您(您的团队)在 OI 的路上一路顺风!!!
┬┴┬┴┤・ω・)ノ ByeBye