【PAT甲】20230304 游记 + 非详细题解 (侵权删)
个人简介
本人就读于浙江某大学,大学期间有 ACM 集训经历。
因为是24考研考生,有认真考虑浙大,想着可以抵机试分数而报了名。
考试
体验感极差。
先说前提:我们学校周末不对学生开放某教学楼= =
因为不想考试被打扰,我在这栋教学楼想办法找了一间空教室作为考试地点。
第一题忘记是啥了,反正是道 easy 题,估计20min之内就拿下了20分。
第二题是模拟题,我写了一百来行,正在调的时候(此时大概过去了1h)突然教室的门被打开了,有几个学生进来说他们借了这间教室开班会,大概半小时之后就开始了,我只能先离开这里再另外找地方。本来考试的要求是考试范围之内两米不能有人,也肯定不能说话,我同时打破了这两条规定,心想不会被浙大拉进黑名单吧,心态直接就崩掉了。我这次考试叫上了我一个室友,以备不时之需,没想到真用上了,室友提醒我先呼叫监考老师再行动,接通之后我向监考老师说明了情况,监考老师倒是对我这边的情况非常宽容,说我可以去找下一个考试的地方,不过要快一点,我室友就拿第二机位 手机 一直拍着我去找地方。由于这栋楼并没有空教室开放,我们最后跑到了顶楼六楼,我坐在楼梯间考完了整场考试。
坐在楼梯间的时候,我不好拿鼠标,就只用了电脑的触控板,debug时对我来说真的很不方便,第二题写的代码又长,我debug了很久,过样例后一交,只有18分,被扣掉了七分。
这时候只有不到一个半小时了,我于是赶紧看下一题,所幸第三题很简单,就是统计一下图中点的入度、出度,我大概10min之内AC了这道题,获得25分。
第四题的简化题意如下:给你一棵树的中序遍历和后序遍历序列,你需要求出这棵树的轮廓,再判断它是不是爱心型的。
思路其实很简单,首先根据中序、后序遍历求出这棵树的结构;然后dfs求树的轮廓;最后判断爱心(轮廓上的点的高度先下降,再上升,再下降,再上升)。
但我在考场上并没有写出这道题。首先是我有点盲目自信,疏于复习,数据结构的知识(尤其是树)我已经忘记了一些,根据中序、后序遍历的序列求树的结构我并没有清晰的思路,只能在考场现推;其次就是我此时的心态已经完全炸裂了,根本静不下心来思考任何有深度的问题,我记得考场上的我知道手算要怎么算,但是转化成代码的时候,我卡在了一个子序列的区间范围的问题上,直到短时间内我觉得做出这题是无望了,就放弃了这道题,去看第二题模拟题。然而第二题我看来看去找不到错误,手造的数据都是可以通过的,我就有些没辙。就这样坐牢到考试结束。 T T
体会
我也算花钱买教训了,这场考试提醒了我该复习数据结构了。
还有 什么煞笔学校周末竟然不对学生开放教室。。我真的很无语
下次如果有这样的考试,还是得走正规流程借教室吧,或者干脆订个钟点房算了。被打扰到真的真的很心梗,崩溃就在一瞬间
第四题题解
我的做法上面已经说过了,就是首先根据中序、后序遍历求出这棵树的结构;然后dfs求树的轮廓;最后判断爱心(轮廓上的点的高度先下降,再上升,再下降,再上升)。
求树的结构
// il ir 和 pl pr 分别是中序、后序遍历序列中子序列的左右区间
// build函数的作用是找到每个当前的子树root的左右儿子,记在L[root], R[root]里,递归求出整棵树的结构
int build(int il, int ir, int pl, int pr) {
if(il > ir || pl > pr) return -1;
int root = P[pr]; // value
int rt = p[root][0]; // pos
int L1 = rt - il, L2 = ir - rt;
L[root] = build(il, rt - 1, pl, pl + L1 - 1);
R[root] = build(rt + 1, ir, pr - L2, pr - 1);
return root;
}
求树的轮廓
我的想法是分步。首先第一部分是只要当前结点有左儿子,就把这个左儿子push_back进ans;第二部分是所有没有儿子的结点;第三部分是从最后一个第二部分的点开始,把它的爸爸依次push进答案
// 写了2个dfs,写一个应该也行的
void dfs(int rt, int fa) { // 先序
// cout << rt << ' ' ;
if(rt == -1) return;
d[rt] = d[fa] + 1;
father[rt] = fa;
if(link && L[rt] != -1 && R[rt] != -1) {link = 0;}
dfs(L[rt], rt);
dfs(R[rt], rt);
return;
}
void dfs2(int rt) {
if(rt == -1) return;
if(State == 1) {
if(L[rt] != -1) {
vis[L[rt]] = 1;
ans.push_back(L[rt]);
}
else State = 2;
}
if(State == 2) {
if(L[rt] == -1 && R[rt] == -1 && !vis[rt]) {
vis[rt] = 1;
ans.push_back(rt);
}
}
dfs2(L[rt]);
dfs2(R[rt]);
}
判断爱心
这就要根据之前dfs求出的点的深度来进行。
bool check() { // 轮廓的 depth 先 + 再 - 再 + 再 -
if(link) return 0;
int depth = d[ans[0]];
int state = 1;
for(int i = 1; i < ans.size(); i++) {
if(state == 1 || state == 3) {
if(d[ans[i]] < depth) state = ((state == 1) ? 2 : 4);
}
else if(state == 2 || state == 4) {
if(d[ans[i]] > depth) state = ((state == 1) ? 2 : 4);
}
depth = d[ans[i]];
}
return (state == 4);
}
最后放一下整个的代码吧,也不知道对不对,求问哪里能提交???
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int L[N], R[N], I[N], P[N], p[N][2], d[N];
int root, father[N], State;
bool link, vis[N];
vector<int> ans;
int build(int il, int ir, int pl, int pr) {
if(il > ir || pl > pr) return -1;
int root = P[pr]; // value
int rt = p[root][0]; // pos
int L1 = rt - il, L2 = ir - rt;
L[root] = build(il, rt - 1, pl, pl + L1 - 1);
R[root] = build(rt + 1, ir, pr - L2, pr - 1);
return root;
}
void dfs(int rt, int fa) { // 先序
// cout << rt << ' ' ;
if(rt == -1) return;
d[rt] = d[fa] + 1;
father[rt] = fa;
if(link && L[rt] != -1 && R[rt] != -1) {link = 0;}
dfs(L[rt], rt);
dfs(R[rt], rt);
return;
}
void dfs2(int rt) {
if(rt == -1) return;
if(State == 1) {
if(L[rt] != -1) {
vis[L[rt]] = 1;
ans.push_back(L[rt]);
}
else State = 2;
}
if(State == 2) {
if(L[rt] == -1 && R[rt] == -1 && !vis[rt]) {
vis[rt] = 1;
ans.push_back(rt);
}
}
dfs2(L[rt]);
dfs2(R[rt]);
}
bool check() { // 轮廓的 depth 先 + 再 - 再 + 再 -
if(link) return 0;
int depth = d[ans[0]];
int state = 1;
for(int i = 1; i < ans.size(); i++) {
if(state == 1 || state == 3) {
if(d[ans[i]] < depth) state = ((state == 1) ? 2 : 4);
}
else if(state == 2 || state == 4) {
if(d[ans[i]] > depth) state = ((state == 1) ? 2 : 4);
}
depth = d[ans[i]];
}
return (state == 4);
}
void print() {
for(auto i : ans) {
printf("%d ", i);
// cout << i << ' ' << d[i] << endl;
}puts("");
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
scanf("%d", &I[i]);
p[I[i]][0] = i;
}
for(int i = 1; i <= n; i++) {
scanf("%d", &P[i]);
p[P[i]][1] = i;
}
root = build(1, n, 1, n);
// cout << "root:" << root << endl;
link = 1;
d[root] = 1;
dfs(root, 0);
State = 1; vis[root] = 1; ans.push_back(root);
dfs2(root);
int tem = ans.back();
while(1) {
tem = father[tem];
if(vis[tem]) break;
ans.push_back(tem);
}
if(check()) {
puts("Yes");
}
else puts("No");
print();
return 0;
}