笔记
depth
,可表示当前层号,但还需要全局变量记录树的层数#include <iostream> #include <cstring> using namespace std; const int N = 110, M = 210, ROOT = 1; int n, m; int h[N], e[M], ne[M], idx; int cnt[N], max_depth; void add(int u, int v) { e[idx] = v; ne[idx] = h[u]; h[u] = idx++; } void dfs(int u, int depth) { if (h[u] == -1) { cnt[depth]++; // 叶节点 max_depth = max(max_depth, depth); return; } for (int p = h[u]; ~p; p = ne[p]) dfs(e[p], depth + 1); } int main() { cin >> n >> m; memset(h, -1, sizeof h); int u, son, k; for (int i = 0; i < m; i++) { cin >> u >> k; while(k--) { cin >> son; add(u, son); } } dfs(ROOT, 0); cout << cnt[0]; for (int i = 1; i <= max_depth; i++) cout << ' ' << cnt[i]; cout << endl; return 0; }
笔记
#include <iostream> #include <unordered_map> using namespace std; const int N = 35; int n; int inorder[N], postorder[N]; unordered_map<int, int> l, r, pos; int build(int in_l, int in_r, int post_l, int post_r) { int root = postorder[post_r]; // 当前后序遍历段的根节点下标 int k = pos[root]; // 根节点在中序遍历的位置(哈希表优化查找) if (in_l < k) { int m = (k - 1) - in_l + 1; // 左子树结点个数 l[root] = build(in_l, k - 1, post_l, post_l + (k - 1 - in_l)); } if (k < in_r) { int m = in_r - (k + 1) + 1; // 右子树结点个数 r[root] = build(k + 1, in_r, post_l + (k - 1 - in_l) + 1, post_r - 1); } return root; } int q[N], hh, tt; void bfs(int root) { q[++tt] = root; while(hh < tt) { int u = q[++hh]; if (l.count(u)) q[++tt] = l[u]; if (r.count(u)) q[++tt] = r[u]; } cout << q[1]; for (int i = 2; i <= n; i++) cout << ' ' << q[i]; cout << endl; } int main() { cin >> n; for (int i = 0; i < n; i++) cin >> postorder[i]; for (int i = 0; i < n; i++) { cin >> inorder[i]; pos[inorder[i]] = i; // 根据结点值查找其中序序列的位置 } int root = build(0, n - 1, 0, n - 1); bfs(root); return 0; }
笔记
#include <iostream> #include <cstring> using namespace std; const int N = 1e4 + 10, M = 2 * N; // 邻接表 int n; int h[N], e[M], ne[M], idx; void add(int u, int v) { e[idx] = v; ne[idx] = h[u]; h[u] = idx++; } // 并查集 int parent[N]; int find(int x) { if (parent[x] != x) parent[x] = find(parent[x]); return parent[x]; } // 树的中心 int d1[N], d2[N], p1[N], up[N]; int dfs_down(int u, int father) { for (int p = h[u]; ~p; p = ne[p]) { int v = e[p]; if (v == father) continue; // 不往上走 int d = 1 + dfs_down(v, u); if (d > d1[u]) { d2[u] = d1[u]; d1[u] = d; p1[u] = v; } else if (d > d2[u]) d2[u] = d; } return d1[u]; } void dfs_up(int u, int father) { for (int p = h[u]; ~p; p = ne[p]) { int v = e[p]; if (v == father) continue; // 不往上走 if (p1[u] == v) up[v] = 1 + max(up[u], d2[u]); // u的最长路径经过v else up[v] = 1 + max(up[u], d1[u]); // u的最长路径不经过v dfs_up(v, u); } } int main() { cin >> n; int u, v; for (int i = 1; i <= n; i++) parent[i] = i; // 初始化并查集 memset(h, -1, sizeof h); // 初始化邻接表 int cnt = n; for (int i = 0; i < n - 1; i++) { cin >> u >> v; add(u, v); add(v, u); if (find(u) != find(v)) { parent[find(u)] = find(v); // 合并 cnt--; } } if (cnt > 1) printf("Error: %d components\n", cnt); else { // 找树的中心(树形DP) dfs_down(1, -1); dfs_up(1, -1); int max_depth = -1; for (int i = 1; i <= n; i++) max_depth = max(max_depth, max(up[i], d1[i])); for (int i = 1; i <= n; i++) if (max(up[i], d1[i]) == max_depth) cout << i << endl; } return 0; }
笔记
#include <iostream> #include <algorithm> using namespace std; const int N = 1010; int n, cnt; int pre[N], in[N], post[N]; bool build(int pre_l, int pre_r, int in_l, int in_r) { if (in_l > in_r) return true; int root = pre[pre_l]; int k; for (k = in_l; k <= in_r; k++) if (in[k] == root) break; // 从前往后找第1个root(重复元素的第1个) if (k > in_r) return false; bool res = true; if(!build(pre_l + 1, pre_l + 1 + (k - 1 - in_l), in_l, k - 1)) res = false; if(!build(pre_l + 1 + (k - 1 - in_l) + 1, pre_r, k + 1, in_r)) res = false; // res = res && build(pre_l + 1, pre_l + 1 + (k - 1 - in_l), in_l, k - 1); // res = res && build(pre_l + 1 + (k - 1 - in_l) + 1, pre_r, k + 1, in_r); post[cnt++] = root; return res; } bool build_r(int pre_l, int pre_r, int in_l, int in_r) { if (in_l > in_r) return true; int root = pre[pre_l]; int k; for (k = in_r; k >= in_l; k--) if (in[k] == root) break; // 从后往前找第1个root(重复元素的最后1个) if (k < in_l) return false; bool res = true; if(!build_r(pre_l + 1, pre_l + 1 + (k - 1 - in_l), in_l, k - 1)) res = false; if(!build_r(pre_l + 1 + (k - 1 - in_l) + 1, pre_r, k + 1, in_r)) res = false; // res = res && build(pre_l + 1, pre_l + 1 + (k - 1 - in_l), in_l, k - 1); // res = res && build(pre_l + 1 + (k - 1 - in_l) + 1, pre_r, k + 1, in_r); post[cnt++] = root; return res; } int main() { cin >> n; for (int i = 0; i < n; i++) { cin >> pre[i]; in[i] = pre[i]; } sort(in, in + n); if (build(0, n - 1, 0, n - 1)) { puts("YES"); cout << post[0]; for (int i = 1; i < n; i++) cout << ' ' << post[i]; cout << endl; } else { reverse(in, in + n); cnt = 0; if (build_r(0, n - 1, 0, n - 1)) { puts("YES"); cout << post[0]; for (int i = 1; i < n; i++) cout << ' ' << post[i]; cout << endl; } else puts("NO"); } return 0; }
笔记
#include <iostream> #include <algorithm> using namespace std; const int N = 1010; int n, a[N], b[N]; int cnt = 1; void inorder(int u) { if (2 * u <= n) inorder(2 * u); b[u] = a[cnt++]; if (2 * u + 1 <= n) inorder(2 * u + 1); } int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + n + 1); inorder(1); // 按中序遍历填入 cout << b[1]; for (int i = 2; i <= n; i++) cout << ' ' << b[i]; return 0; }
笔记
push
,压入的元素一定是root
push
,则当前结点是上一个结点的左孩子pop
,则当前结点是上一个结点的右孩子root
开始输出其后序遍历次序#include <iostream> #include <stack> using namespace std; const int N = 35; int n, l[N], r[N]; // 左右孩子 string output; void post_order(int u) { if (!u) return; // 空节点 post_order(l[u]); post_order(r[u]); output += to_string(u) + " "; } int main() { cin >> n; stack<int> s; string op; int root, x; int last = 0; // 上一个结点 int type = 0; // 0表示push,1表示pop for (int i = 0; i < 2 * n; i++) { cin >> op; if (op == "Push") { cin >> x; if (!i) root = x; // 首次压入是根节点 else { if (type == 0) l[last] = x; // 上次是push,当前结点是上个结点的左孩子 else r[last] = x; // 上次是pop,当前结点是上个结点的左孩子 } s.push(x); // 模拟栈压入 last = x; type = 0; } else { // pop last = s.top(); // 模拟栈弹出 s.pop(); type = 1; } } post_order(root); cout << output.substr(0, output.size() - 1) << endl; // 去掉末尾空格 return 0; }
笔记
~p
等价于p != -1
#include <iostream> #include <algorithm> using namespace std; const int N = 110, ROOT = 0; int n, l[N], r[N], w[N], a[N]; int cnt; void inorder(int u) { if (u == -1) return; inorder(l[u]); a[u] = w[cnt++]; // 填数 inorder(r[u]); } string res; int q[N]; void bfs(int root) { int hh = 0, tt = 0; q[++tt] = root; while(hh < tt) { int x = q[++hh]; if (l[x] != -1) q[++tt] = l[x]; if (r[x] != -1) q[++tt] = r[x]; } for (int i = 1; i <= n; i++) res += to_string(a[q[i]]) + " "; } int main() { cin >> n; for (int i = 0; i < n; i++) cin >> l[i] >> r[i]; for (int i = 0; i < n; i++) cin >> w[i]; sort(w, w + n); inorder(ROOT); // 中序遍历填数 bfs(ROOT); cout << res.substr(0, res.size() - 1) << endl; return 0; }
笔记
方法1 不翻转
#include <iostream> #include <cstring> using namespace std; const int N = 15; int n, l[N], r[N]; bool has_father[N]; string res_1; int q[N]; void bfs(int root) { int hh = 0, tt = 0; q[++tt] = root; while(hh < tt) { int x = q[++hh]; if (~r[x]) q[++tt] = r[x]; if (~l[x]) q[++tt] = l[x]; } for (int i = 1; i <= n; i++) res_1 += to_string(q[i]) + " "; } string res_2; void inorder(int u) { if (u == -1) return; inorder(r[u]); res_2 += to_string(u) + " "; inorder(l[u]); } int main() { cin >> n; memset(l, -1, sizeof l); memset(r, -1, sizeof r); string ls, rs; for (int i = 0; i < n; i++) { cin >> ls >> rs; if (ls != "-") { l[i] = ls[0] - '0'; has_father[l[i]] = true; } if (rs != "-") { r[i] = rs[0] - '0'; has_father[r[i]] = true; } } int root = -1; for (int i = 0; i < n; i++) if (!has_father[i]) { root = i; break; } bfs(root); inorder(root); cout << res_1.substr(0, res_1.size() - 1) << endl; cout << res_2.substr(0, res_2.size() - 1) << endl; return 0; }
方法2 翻转
#include <iostream> #include <cstring> using namespace std; const int N = 15; int n, l[N], r[N]; bool has_father[N]; void reverse(int u) { if (u == -1) return; reverse(l[u]); reverse(r[u]); swap(l[u], r[u]); } string res_1; int q[N]; void bfs(int root) { int hh = 0, tt = 0; q[++tt] = root; while(hh < tt) { int x = q[++hh]; if (~l[x]) q[++tt] = l[x]; if (~r[x]) q[++tt] = r[x]; } for (int i = 1; i <= n; i++) res_1 += to_string(q[i]) + " "; } string res_2; void inorder(int u) { if (u == -1) return; inorder(l[u]); res_2 += to_string(u) + " "; inorder(r[u]); } int main() { cin >> n; memset(l, -1, sizeof l); memset(r, -1, sizeof r); string ls, rs; for (int i = 0; i < n; i++) { cin >> ls >> rs; if (ls != "-") { l[i] = ls[0] - '0'; has_father[l[i]] = true; } if (rs != "-") { r[i] = rs[0] - '0'; has_father[r[i]] = true; } } int root = -1; for (int i = 0; i < n; i++) if (!has_father[i]) { root = i; break; } reverse(root); bfs(root); inorder(root); cout << res_1.substr(0, res_1.size() - 1) << endl; cout << res_2.substr(0, res_2.size() - 1) << endl; return 0; }
笔记
#include <iostream> #include <cstring> using namespace std; const int N = 25; int n, l[N], r[N]; bool has_father[N]; int max_u = -1, max_k = -1; void dfs(int u, int k) { if (u == -1) return; if (k > max_k) { max_u = u; max_k = k; } dfs(l[u], 2 * k); dfs(r[u], 2 * k + 1); } int main () { cin >> n; memset(l, -1, sizeof l); memset(r, -1, sizeof r); string ls, rs; for (int i = 0; i < n; i++) { cin >> ls >> rs; if (ls != "-") { l[i] = stoi(ls); has_father[l[i]] = true; } if (rs != "-") { r[i] = stoi(rs); has_father[r[i]] = true; } } int root = 0; while(has_father[root]) root++; dfs(root, 1); // 从1开始填完全二叉树 if (max_k == n) printf("YES %d\n", max_u); else printf("NO %d\n", root); return 0; }
笔记
insert(int& u, int x)
可自动更新左右子树指针#include <iostream> using namespace std; const int N = 1010; int n, l[N], r[N], v[N], idx; int cnt[N], max_depth; void insert(int &u, int x) { // 从结点u开始插入x if (!u) { // 首次插入 u = ++idx; // 计算可用结点位置(数组下标表示),并保存(引用可修改变量) v[u] = x; // 保存该结点 } else if (x <= v[u]) insert(l[u], x); // 若插入成功,则会修改l[u]的值,指向新结点地址 else insert(r[u], x); // 若插入成功,则会修改r[u]的值,指向新结点地址 } void dfs(int u, int depth) { if (!u) return; cnt[depth]++; max_depth = max(max_depth, depth); dfs(l[u], depth + 1); dfs(r[u], depth + 1); } int main() { cin >> n; int x; int root = 0; // 0表示首次插入 for (int i = 0; i < n; i++) { cin >> x; insert(root, x); // 自动更新当前root位置 } dfs(root, 0); int n1 = cnt[max_depth], n2 = cnt[max_depth - 1]; printf("%d + %d = %d\n", n1, n2, n1 + n2); return 0; }
笔记
#include <iostream> using namespace std; const int N = 40; int pre[N], post[N], in[N]; // 返回合法方案数 int dfs(int pre_l, int pre_r, int post_l, int post_r, string& res) { if (pre_l > pre_r) return 1; // 合法情况 if (pre[pre_l] != post[post_r]) return 0; // 非法情况 int cnt = 0; for (int k = pre_l; k <= pre_r; k++) { string l_res, r_res; int l_cnt = dfs(pre_l + 1, k, post_l, post_l + k - pre_l - 1, l_res); int r_cnt = dfs(k + 1, pre_r, post_l + k - pre_l - 1 + 1, post_r - 1, r_res); if (l_cnt && r_cnt) { cnt += l_cnt * r_cnt; res = l_res + to_string(pre[pre_l]) + " " + r_res; if (cnt > 1) break; } } return cnt; } int main() { int n; cin >> n; for (int i = 0; i < n; i++) cin >> pre[i]; for (int i = 0; i < n; i++) cin >> post[i]; string res; int cnt = dfs(0, n - 1, 0, n - 1, res); if (cnt > 1) puts("No"); else puts("Yes"); cout << res.substr(0, res.size() - 1) << endl; return 0; }
笔记
BFS
中确定二叉树每一层结点的范围,内嵌一层while
即可做到#include <iostream> #include <algorithm> #include <unordered_map> using namespace std; const int N = 35; unordered_map<int, int> l, r, pos; // 左右孩子 int n, in[N], post[N]; int build(int in_l, int in_r, int post_l, int post_r) { int root = post[post_r]; int k = pos[root]; // 查找root在中序遍历的下标 if (in_l < k) l[root] = build(in_l, k - 1, post_l, post_l + k - 1 - in_l); if (k < in_r) r[root] = build(k + 1, in_r, post_l + k - 1 - in_l + 1, post_r - 1); return root; } string res; int q[N]; void bfs(int root) { int hh = 0, tt = 0; q[0] = root; bool flag = true; while(hh <= tt) { int head = hh, tail = tt; while(hh <= tail) { int u = q[hh++]; if (l.count(u)) q[++tt] = l[u]; if (r.count(u)) q[++tt] = r[u]; } if (flag) reverse(q + head, q + tail + 1); flag = !flag; } for (int i = 0; i < n; i++) res += to_string(q[i]) + ' '; res.pop_back(); } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; for (int i = 0; i < n; i++) { cin >> in[i]; pos[in[i]] = i; // 哈希表,加快查找下标 } for (int i = 0; i < n; i++) cin >> post[i]; int root = build(0, n - 1, 0, n - 1); bfs(root); cout << res << endl; return 0; }
笔记
#include <iostream> #include <unordered_map> using namespace std; const int N = 5e4 + 10; unordered_map<int, int> pos; int n, in[N], pre[N]; int post; // 后序遍历第1个结点 void build(int in_l, int in_r, int pre_l, int pre_r) { int root = pre[pre_l]; int k = pos[root]; if (in_l < k) build(in_l, k - 1, pre_l + 1, pre_l + 1 + k - 1 - in_l); if (k < in_r) build(k + 1, in_r, pre_l + 1 + k - 1 - in_l + 1, pre_r); if (!post) post = root; // 后序遍历第1个结点 } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; for (int i = 0; i < n; i++) cin >> pre[i]; for (int i = 0; i < n; i++) { cin >> in[i]; pos[in[i]] = i; } build(0, n - 1, 0, n - 1); cout << post << endl; return 0; }
笔记
&
#include <iostream> #include <cstring> using namespace std; const int N = 30; int l[N], r[N], w[N], idx; // 左右儿子法实现平衡二叉树 int h[N]; // 树高 int get_balance(int u) { return h[l[u]] - h[r[u]]; // 平衡度 } void update(int u) { h[u] = max(h[l[u]], h[r[u]]) + 1; // 更新结点高度 } void R(int& u) { int p = l[u]; l[u] = r[p]; // 不然左孩子的右孩子不为空,放不了根节点 r[p] = u; update(u); // 从下往上更新 update(p); u = p; // 更新根节点 } void L(int& u) { int p = r[u]; r[u] = l[p]; // 不然左孩子的右孩子不为空,放不了根节点 l[p] = u; update(u); // 从下往上更新 update(p); u = p; // 更新根节点 } void insert(int &u, int v) { if (!u) { u = ++idx; w[u] = v; } else if (v < w[u]) { // 先插入,再调整,最后更新 insert(l[u], v); if (get_balance(u) == 2) { if (get_balance(l[u]) == 1) R(u); else { L(l[u]); R(u); } } } else { insert(r[u], v); if (get_balance(u) == -2) { if (get_balance(r[u]) == -1) L(u); else { R(r[u]); L(u); } } } update(u); } int main() { int n, v; cin >> n; int root = 0; // 从第0个位置开始插入 for (int i = 0; i < n; i++) { cin >> v; insert(root, v); // 插入到平衡二叉树中 } cout << w[root] << endl; return 0; }
笔记
#include <iostream> using namespace std; const int N = 25; int n, l[N], r[N], w[N], h[N], idx; int get_balance(int u) { return h[l[u]] - h[r[u]]; } void update(int u) { h[u] = max(h[l[u]], h[r[u]]) + 1; } void R(int& u) { int p = l[u]; l[u] = r[p]; r[p] = u; update(u); update(p); u = p; } void L(int& u) { int p = r[u]; r[u] = l[p]; l[p] = u; update(u); update(p); u = p; } void insert(int& u, int x) { if (!u) { u = ++idx; w[u] = x; } else if (x < w[u]) { insert(l[u], x); if (get_balance(u) == 2) { if (get_balance(l[u]) == 1) R(u); else { L(l[u]); R(u); } } } else { insert(r[u], x); if (get_balance(u) == -2) { if (get_balance(r[u]) == -1) L(u); else { R(r[u]); L(u); } } } update(u); } int q[N], pos[N]; void bfs(int root) { int hh = 0, tt = -1; q[++tt] = root; pos[root] = 1; // 模拟完全二叉树 bool flag = true; // 是否是二叉树 while(hh <= tt) { int u = q[hh++]; if (pos[u] > n) flag = false; // 超出完全二叉树的保存范围 if (l[u]) { q[++tt] = l[u]; pos[l[u]] = 2 * pos[u]; } if (r[u]) { q[++tt] = r[u]; pos[r[u]] = 2 * pos[u] + 1; } } string res; for (int i = 0; i < n; i++) res += to_string(w[q[i]]) + ' '; res.pop_back(); cout << res << endl; if (flag) puts("YES"); else puts("NO"); } int main() { cin >> n; int x, root = 0; for (int i = 0; i < n; i++) { cin >> x; insert(root, x); } bfs(root); }
笔记
#include <iostream> #include <algorithm> #include <unordered_map> using namespace std; const int N = 35; int n, pre[N], in[N]; unordered_map<int, int> pos; bool flag; int build(int pre_l, int pre_r, int in_l, int in_r, int& sum) { int root = pre[pre_l]; int k = pos[abs(root)]; if (k < in_l || k > in_r) { flag = false; return 0; } int left = 0, right = 0, ls = 0, rs = 0; if (k > in_l) left = build(pre_l + 1, pre_l + 1 + k - 1 - in_l, in_l, k - 1, ls); if (k < in_r) right = build(pre_l + 1 + k - 1 - in_l + 1, pre_r, k + 1, in_r, rs); if (ls != rs) flag = false; // 黑结点个数不等 sum = ls; // 更新sum的值 if (root < 0) { if (left < 0 || right < 0) flag = false; // 红色根节点存在黑结点孩子 } else sum++; // 根节点是黑结点,到叶节点的黑结点个数+1 return root; } int main() { int t; cin >> t; while(t--) { cin >> n; for (int i = 0; i < n; i++) { cin >> pre[i]; in[i] = abs(pre[i]); } sort(in, in + n); // for (int i = 0; i < n; i++) cout << pre[i] << endl; for (int i = 0; i < n; i++) pos[in[i]] = i; int sum = 0; flag = true; int root = build(0, n - 1, 0, n - 1, sum); if (root < 0) flag = false; if (flag) puts("Yes"); else puts("No"); pos.clear(); } return 0; }
笔记
#include <iostream> #include <vector> #include <algorithm> using namespace std; const int N = 110, ROOT = 0; int n, m, target; // 结点个数,非叶子结点个数,目标权值 int w[N]; // 权重 bool g[N][N]; // 邻接矩阵存储多叉树 bool is_leaf[N]; // 是否是叶节点 vector<vector<int>> res; void dfs(int u, int s, vector<int>& path) { if (is_leaf[u] && s == target) res.push_back(path); else { for (int v = 0; v < n; v++) if (g[u][v]) { path.push_back(w[v]); dfs(v, s + w[v], path); path.pop_back(); } } } int main() { cin >> n >> m >> target; for (int i = 0; i < n; i++) cin >> w[i]; while(m--) { int u, k, v; cin >> u >> k; is_leaf[u] = true; // 先标记非叶节点,等会儿再处理 while(k--) { cin >> v; g[u][v] = true; // 构造邻接矩阵 } } for (int i = 0; i < n; i++) is_leaf[i] = !is_leaf[i]; // 变成正确含义 vector<int> path{w[ROOT]}; dfs(ROOT, w[ROOT], path); sort(res.begin(), res.end(), greater<vector<int>>()); for (auto elem : res) { string line; for (int item : elem) line += to_string(item) + ' '; line.pop_back(); cout << line << endl; } return 0; }
笔记
queue
实现,还可以用vector
实现#include <iostream> #include <vector> using namespace std; const int N = 110, ROOT = 1; int n, m; // 结点个数,非叶子结点个数 bool g[N][N]; // 邻接矩阵 vector<int> level[N]; void bfs(int root) { int l = 1; level[1].push_back(root); while(level[l].size()) { for (auto u : level[l]) for (int v = 1; v <= n; v++) if (g[u][v]) level[l + 1].push_back(v); l++; } int max_l = 0, max_nodes = 0; for (int i = 1; i < l; i++) if (max_nodes < level[i].size()) { max_l = i; max_nodes = level[i].size(); } cout << max_nodes << ' ' << max_l << endl; } int main() { cin >> n >> m; while(m--) { int u, k, v; cin >> u >> k; while(k--) { cin >> v; g[u][v] = true; } } bfs(ROOT); return 0; }