【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;
}
posted @ 2023-03-06 00:25  starlightlmy  阅读(18)  评论(0编辑  收藏  举报