2023冬季PAT 甲级 两小时AK 考后回想

这次题目大都比较基础,做的比较顺利。

2023冬季PAT题目

第一题 A-1 Fill in the Numbers

This is one of the questions given in Harvard-MIT Math Tournament in 2014: The integers 1, 2, …, 64 are written in the squares of a 8×8 chess board, such that for each 1≤i<64, the numbers i and i+1 are in squares that share an edge. What is the largest possible sum that can appear along one of the diagonals? (Note: 64 and 1 must also be in squares that share an edge.)
This is hard … Fortunately you are not asked to solve this problem by writing a program.
Your job is to check if any given plan of filling satisfies the constrains, and among all the given plans, find the one that satisfies the constrains with the largest diagonal sum.

Input Specification:
Each input file contains one test case. For each case, the first line gives 2 positive integers: n (≤100) and m (≤20), which are the size of the chess board (i.e. the chess board has n×n squares) and the number of plans given, respectively. Since it is simple to prove that there is no solution for any odd number n, it is guaranteed that the input n is an even number.
Then m plans are given, each occupies n lines, with n numbers no more than n^2 given in each line. The numbers in a line are separated by a space.

Output Specification:
For each test case, first print in a line the number of plans that satisfy the constrains with the largest diagonal sum. Then output in the next line in increasing order the indices of these plans (the plans are indexed from 1 to m as in the input order).
Note: all the numbers in a line must be separated by 1 space, and there must be no extra space at the beginning or the end of the line.

Sample Input:

4 5
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 6
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 10
15 16 1 2
14 13 4 3
11 12 5 6
10 9 8 7
3 4 5 6
2 13 12 7
1 14 11 8
16 15 10 9
10 5 4 3
7 12 13 2
8 11 14 1
9 6 15 16

Sample Output:

2
1 4

第一题首先咋呼人,实际上就是给定一群nXn矩阵,其中的值需要是1~n*n,而且需要第n个数字与第n+1个数字相邻,找出满足以上条件并且拥有最大对角线的方案。这题我用哈希表<int,pair<int,int>>存每个值对应的位置,这样判断相邻可以用 横坐标差的绝对值加纵坐标差的绝对值 与 1 比较来判断是否相邻。这里对角线的单词可能有人不认识(diag什么的),但是线性代数正好见过,所以就用了正对角线和副对角线和的最大值来更新就可以。

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
const int N = 110;
int a[N][N];
unordered_map<int,pair<int,int>> Hash;
vector<int> res;

int n,m,l_sum;
int main()
{
    cin >> n >> m;
    for(int i = 1;i <= m;i++)
    {
        bool flag = true;
        Hash.clear();
        for(int j = 1;j <= n;j++)
            for(int k = 1;k <= n;k++)
            {
                cin >> a[j][k];
                if(Hash.count(a[j][k])) flag = false;
                Hash[a[j][k]] = {j,k};
            }
        for(int j = 1;j <= n*n;j++)
        {
            auto p1 = Hash[j];
            auto p2 = Hash[j == n*n?1:j+1];
            if(abs(p1.first-p2.first) + abs(p1.second - p2.second) != 1) flag = false;
        }
        if(!flag) continue;
        int diag = 0,rdiag = 0;
        for(int j = 1;j <= n;j++) diag += a[j][j],rdiag += a[j][n-j+1];
        if(max(diag,rdiag) > l_sum)
        {
            l_sum = max(diag,rdiag);
            res.clear();
            res.push_back(i);
        }
        else if(max(diag,rdiag) == l_sum) res.push_back(i);
    }
    cout << res.size() << endl;
    for(int i = 0;i < res.size();i++)
    {
        if(i) cout << " ";
        cout << res[i];
    }
}

第二题 A-2 PeekMax in Stack

A stack is a First-In-Last-Out linear structure. Here you are supposed to implement a special function that allows you to find the maximum key value (PeekMax) in a stack, besides the normal Push and Pop. The point is, this new function must not slow down the overall performance of this stack.

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer n (≤10^5), which is the number of operations. Then n lines follow, each gives an operation in the format:
Push X, means to push element X onto the stack, where X is an integer of which the absolute value is no more than 2^30;
Pop means to pop the top element out of the stack;
PeekMax means to return the maximum value of the keys in the current stack.

Output Specification:
For each operation, execute as it is defined. For each Pop, print in a lien the key value of the popped element; and for each PeekMax, print in a line the maximum value of the keys in the current stack. If the stack is empty when Pop or PeekMax is called, output ERROR instead.
It is guaranteed that there is at least one line of output.

Sample Input:

11
Pop
Push 34
Push 28
PeekMax
Push 84
PeekMax
Pop
PeekMax
Pop
Pop
PeekMax

Sample Output:

ERROR
34
84
84
34
28
34
ERROR

第二题很简单,acwing和leetcode都见过,模拟一个栈并且可以快速给出栈中的最大值。开两个栈即可,一个普通栈,一个从顶向下递减的栈。

#include<iostream>
#include<stack>
using namespace std;

stack<int> stk1,stk2;
int n;

int main()
{
    cin >> n;
    while(n--)
    {
        string s;
        cin >> s;
        if(s == "Pop")
        {
            if(!stk1.size())
            {
                puts("ERROR");
                continue;
            }
            auto t = stk1.top();
            stk1.pop();
            if(t == stk2.top())
                stk2.pop();
            printf("%d\n",t);
        }
        if(s == "PeekMax")
        {
            if(!stk2.size())
            {
                puts("ERROR");
                continue;
            }
            printf("%d\n",stk2.top());
        }
        if(s == "Push")
        {
            int t;
            scanf("%d",&t);
            stk1.push(t);
            if(!stk2.size() || t >= stk2.top()) stk2.push(t);
        }
    }
}

第三题 A-3 A+B with Binary Search Trees

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
Both the left and right subtrees must also be binary search trees.
Given two binary search trees T1 and T2, and an integer N, you are supposed to find a number A from T1 and B from T2 such that A+B=N.

Input Specification:
Each input file contains one test case. Each case gives the information of T1, T2 and N, in the following format:
The first line contains a positive integer n1(≤2×105), which is the number of nodes in T1. Then n1 lines follow, where the ith line contains the key value k (−2×109≤k≤2×109) and the parent node index of the ith node (0≤i<n1). Since the root has no parent, its parent index is defined to be −1.
After T1, T2 is given in the same format of T1.
Finally the last line gives the target N (with the same range of k).

Output Specification:
For each test case, print in a line true if at least one solution does exist, then output all the solutions in the following lines, each in the format N = A + B. In case the solution is not unique, you must output them in ascending order of the values of A. Note: the same equation should be printed only once. If there is no solution, simply print false.
Then print in the last two lines the preorder traversal sequences of T1 and T2, respectively. The values in each line are separated by 1 space, and there must be no extra space at the beginning or the end of the line.

Sample Input 1:

8
12 2
16 5
13 4
18 5
15 -1
17 4
14 2
18 3
7
20 -1
16 0
25 0
13 1
18 1
21 2
28 2
36

Sample Output 1:

true
36 = 15 + 21
36 = 16 + 20
36 = 18 + 18
15 13 12 14 17 16 18 18
20 16 13 18 25 21 28

Sample Input 2:

5
10 -1
5 0
15 0
2 1
7 1
3
15 -1
10 0
20 0
40

Sample Output 2:

false
10 5 2 7 15
15 10 20

第三题考二叉树很恶心,一个测试点卡了半天。题目是给出两个二叉搜索树的节点数以及各节点的值和父节点。要求从第一棵树找A,从第二棵树找B,在给定C的情况下找出A+B=C的所有方案。结点范围是10^5,所以肯定是双指针了,每棵树快排可能会超时,所以我直接中序遍历拿到递增序列再双指针,因为还要重建树还要最后前序遍历,用太多的STL很可能超时,所以改了半天才AC。

#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;
const int N = 200010;
typedef long long LL;

int n1,n2;
LL target;
int e1[N],e2[N];
int f1[N],f2[N];
unordered_map<int,int> l1,r1,l2,r2;
vector<int> v1,v2;
vector<pair<int,int>> res;
int root1,root2;

void dfs1(int root)
{
    if(l1.count(root)) dfs1(l1[root]);
    v1.push_back(e1[root]);
    if(r1.count(root)) dfs1(r1[root]);
}

void dfs2(int root)
{
    if(l2.count(root)) dfs2(l2[root]);
    v2.push_back(e2[root]);
    if(r2.count(root)) dfs2(r2[root]);
}

void dfs3(int root)
{
    v1.push_back(e1[root]);
    if(l1.count(root)) dfs3(l1[root]);
    if(r1.count(root)) dfs3(r1[root]);
}

void dfs4(int root)
{
    v2.push_back(e2[root]);
    if(l2.count(root)) dfs4(l2[root]);
    if(r2.count(root)) dfs4(r2[root]);
}

int main()
{
    cin >> n1;
    for(int i = 0;i < n1;i++) scanf("%d%d",&e1[i],&f1[i]);
    for(int i = 0;i < n1;i++)
        if(f1[i] == -1) root1 = i;
        else if(e1[i] < e1[f1[i]]) l1[f1[i]] = i;
        else if(e1[i] >= e1[f1[i]]) r1[f1[i]] = i;
    dfs1(root1);
    cin >> n2;
    for(int i = 0;i < n2;i++) scanf("%d%d",&e2[i],&f2[i]);
    for(int i = 0;i < n2;i++)
        if(f2[i] == -1) root2 = i;
        else if(e2[i] < e2[f2[i]]) l2[f2[i]] = i;
        else if(e2[i] >= e2[f2[i]]) r2[f2[i]] = i;
    dfs2(root2);
    cin >> target;
    for(int i = 0,j = v2.size()-1;i < v1.size();i++)
    {
        while(j >= 0 && (LL)v1[i] + v2[j] > target) j--;
        if(j < 0) break;
        if((LL)v1[i] + v2[j] == target)
        {
            if(!res.size() || res.back().first != v1[i]) res.push_back({v1[i],v2[j]});
        }
    }
    if(res.size())
    {
        puts("true");
        for(int i = 0;i < res.size();i++) printf("%d = %d + %d\n",target,res[i].first,res[i].second);
    }
    else puts("false");
    v1.clear();
    v2.clear();
    dfs3(root1);
    dfs4(root2);
    for(int i = 0;i < v1.size();i++)
    {
        if(i) cout << " ";
        cout << v1[i];
    }
    puts("");
    for(int i = 0;i < v2.size();i++)
    {
        if(i) cout << " ";
        cout << v2[i];
    }
}


第四题 A-4 Transportation Hub

Given the map of a country, there could be more than one shortest path between any pair of cities. A transportation hub is a city that is on no less than k shortest paths (the source and the destination NOT included). Your job is to find, for a given pair of cities, the transportation hubs on the way.
Note: the shortest path length from v to itself is defined to be 0.

Input Specification:
Each input file contains one test case. For each case, the first line gives three positive integers n (3≤n≤500), m and k (1<k≤5), being the total number of cities, the number of roads connecting those cities, and the threshold (阈值) for a transportation hub, respectively. Then m lines follow, each describes a road in the format:

c1 c2 length

where c1 and c2 are the city indices (from 0 to n−1) of the two ends of the road; length is the length of the road, which is a positive integer that is no more than 100. It is guaranteed that all the roads are two-way roads, and there is no duplicated information for any road.
Then another positive integer T (≤500) is given, followed by T lines, each gives a pair of source and destination.

Output Specification:
For each pair of source and destination, list all the transportation hubs in ascending order of their indices, in a line. All the numbers in a line must be separated by 1 space, and there must be no extra space at the beginning or the end of the line.
In case that there is no transportation hub, simply print None in the line.

Sample Input:

10 16 2
1 2 1
1 3 1
1 4 2
2 4 1
2 5 2
3 4 1
3 0 1
4 5 1
4 6 2
5 6 1
7 3 2
7 8 1
7 0 3
8 9 1
9 0 2
0 6 2
3
1 6
7 0
5 5

Sample Output:

2 3 4 5
None
None

第四题是最短路问题,两个节点之中可能有多条最短路,如果所有最短路经过一个节点的次数和大于给定的k,那么这个节点就会被标记,给结点数,边数,无向边的情况和多个起点终点,求每个起点终点之间被标记的所有节点。直接dijkstra算法,这里怎么计算每个节点路过多少次呢,我用的是vector<vector<int>> paths[N]存储最短路的所有路径,再遍历每条路径给结点++,这样时间复杂度有点高,其实直接用vector<int> times[N]存储到每个结点最短路经过各节点的次数,这样维护也比较容易。

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 510;

int d[N][N];
bool st[N];
int n,m,k,T;
vector<vector<int>> paths[N];
int dist[N],nums[N];

void dijkstra(int root)
{
    memset(dist,0x3f,sizeof dist);
    memset(nums,0,sizeof nums);
    memset(st,0,sizeof st);
    for(int i = 0;i < n;i++) paths[i].clear();

    dist[root] = 0,paths[root] = {{root}};

    for(int i = 0;i < n;i++)
    {
        int t = -1;
        for(int j = 0;j < n;j++)
            if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
        st[t] = true;
        for(int j = 0;j < n;j++)
            if(dist[t] + d[t][j] < dist[j])
            {
                dist[j] = dist[t] + d[t][j];
                paths[j] = paths[t];
                for(int k = 0;k < paths[j].size();k++)
                    paths[j][k].push_back(j);
            }
            else if(dist[t] + d[t][j] == dist[j])
            {
                for(int k = 0;k < paths[t].size();k++)
                {
                    auto v = paths[t][k];
                    v.push_back(j);
                    paths[j].push_back(v);
                }
            }
            
    }
}

int main()
{
    memset(d,0x3f,sizeof d);
    cin >> n >> m >> k;
    while(m--)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        d[a][b] = d[b][a] = c;
    }
    cin >> T;
    while(T--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        dijkstra(a);
        for(int i = 0;i < paths[b].size();i++)
        {
            for(int j = 0;j < paths[b][i].size();j++)
            {
                nums[paths[b][i][j]]++;
            }
        }
        string res = "";
        for(int i = 0;i < n;i++)
            if(nums[i] >= k && i != a && i != b) res += to_string(i) + " ";
        if(res == "") puts("None");
        else
        {
            res.pop_back();
            cout << res << endl;
        }
    }
}

总之PAT的题目大多并没有考察很难想的算法,对于打基础是非常有用的。

备考建议

我的算法学习路线起步路线是acwing的课和leetcode的题,之前闷头刷题其实提升不是很大,很多算法主要是理解并记住模板,acwing的算法基础课用来入门非常非常的好,有一定算法积累和代码风格后刷PAT也会很快,我从11月中旬到今天保持每天12题左右,刷穿题库对拿高分很有帮助。
在这里插入图片描述

  • 34
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值