2024 秋季PAT認證甲級(題解A-D)
寫在前面
這一次PAT甲級應該是最近幾次最簡單的一次了,3個小時的比賽差不多30分鐘就ak了(也是拿下了整場比賽的rk1),下面是題解報告,每個題目差不多都是20-30行程式碼,難度在洛谷普及組左右(cf 1000-1200分)
A. A-1 Happy Patting
題目描述
The "Happy Patting" game is to arrange the children into n rows, with m people in each row. When the game starts, each child will receive a digital command on his/her mobile phone simultaneously: 1 for forward, 2 for backward, 3 for left, and 4 for right. The children must follow the command to pat the children in the specified direction. How many children are patted by more than one friend?
Note: In the plane diagram, the top of a grid is "front" and the bottom is "back". Children in the corners may pat the air, which is also allowed.
輸入
Each input file contains one test case. The first line gives 2 positive integers n and m (2≤n,m≤100), which are the number of rows and the number of people in each row, respectively.
Then n lines follow, each contains m numbers, which represent the digital commands received by the children at the corresponding position.
All the numbers in a line are separated by a space.
輸入
For each test case, print in a line the number of children who are patted by more than one friend.
樣例
in:
3 5
1 2 3 4 1
4 1 4 3 3
3 2 1 1 3
out:
4
題意簡述
給一個\(n * m\)的矩陣,每個矩陣上有一個數字,代表這個格子上的孩子向哪個方移動,最後問所有格子中,有多少個格子上有超過1個孩子
思路
直接模擬,使用一個二維陣列來存每個位置孩子的數量,每次輸入一個數,代表當前位置的孩子會向目標位置的格子移動,讓目標位置的孩子數+1即可,最後遍歷二維陣列,統計大於1的數的個數即可(如果越界就不記錄)
AC程式碼
#include<bits/stdc++.h>
using namespace std;
int main()
{
cin.tie(0) -> sync_with_stdio(0);
int n, m;
cin >> n >> m;
vector<vector<int>> graph(n + 1, vector<int>(m + 1));
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m ; j ++)
{
int t;
cin >> t;
int x = i, y = j;
if(t == 1) x --;
if(t == 2) x ++;
if(t == 3) y --;
if(t == 4) y ++;
if(x < 1 || x > n || y < 1 || y > m) continue;
graph[x][y]++;
}
int ans = 0;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m ; j ++)
ans += graph[i][j] > 1;
cout << ans;
}
B. A-2 Baggage Carousel
題目描述
When a flight arrives, the passengers will go to the Arrivals area to pick up their luggages from a baggage carousel(行李轉盤).
Now assume that we have a special airport that has only one pickup window for each baggage carousel. The passengers are asked to line up to pick up their luggage one by one at the window. The carousel can hold at most m luggages, and each luggage has a unique tag number. When a passenger's tag number is matched by a luggage on the carousel, the luggage is then handed to the passenger and the next luggage will be sent onto the carousel.
But if one arrives at the window yet finds out that one's luggage is not on the carousel, one will have to move to the end of the queue and wait for the next turn. Suppose that each turn takes 1 minute, your job is to calculate the total time taken to clear the baggage carousel.
輸入
Each input file contains one test case. The first line gives 2 positive integers \(n\) (≤500) and \(m\) (≤50), which are the number of passengers and the size of the baggage carousel, respectively.
Then n distinct tag number are given in the next line, each is an 8-digit number. The tag numbers are given in the order of being sent to the carousel. It is assumed that \(min(n,m)\) luggages are already on the carousel at the beginning.
The next line gives another sequence of n distinct tag numbers, which corresponds to the passengers in the queue.
All the numbers in a line are separated by a space.
輸出
For each test case, print in a line the total time taken to clear the baggage carousel.
NOTE
If the tag number of a passenger cannot be found at all, that means the passenger's luggage is lost. In this case you must output in a line TagNumber is lost! where TagNumber is the tag number, and then remove this passenger from the queue right away. Since the number of luggages is the same as the number of passengers, if one passenger's luggage is lost, there must be one luggage left and the carousel can never be cleared. In this case, output in the last line the total time taken to clear the passengers' queue.
樣例
in1:
10 4
00000001 00000002 00000003 00000004 00000005 00000006 00000007 00000008 00000009 00000010
00000010 00000008 00000006 00000001 00000004 00000007 00000003 00000009 00000005 00000002
out1:
16
in2:
10 4
00000001 00000002 00000003 00000004 00000005 00000006 00000007 00000008 00000009 00000010
00000008 12345678 00000006 00000001 00000004 00000007 87654321 00000009 00000005 00000002
out2:
12345678 is lost!
87654321 is lost!
14
題意簡述
有\(n\)個人以及\(n\)個行李和一個能放最多\(m\)件行李的行李轉盤,人和行李有唯一的編號,人按照給定順序進行排隊,行李按照給定順序上行李轉盤,每次佇列最前面的人走上行李轉盤,如果行李轉盤上有他的行李,那麼他會拿著行李直接離開,如果沒有找到他的行李,就會回到佇列的末尾,重新排隊,但是如果他的行李不在這\(n\)件行李之中,你應該報告他的行李丟失了,然後他會直接離開。每個人走上前檢視行李轉盤操作的時間記作一個單位,問所有的人都離開時需要多少時間。
思路
本題實際上要你模擬一個行李轉盤(可以用set維護),和兩個佇列(一個行李的佇列和人的佇列),首先可以用map容器記錄出現過的每個行李,從行李佇列中取出\(min(m, n)\)件行李放入行李轉盤,每次取出人佇列的隊頭,首先查詢map中是否有這個人的行李,如果沒有說明這個人的行李丟失了,直接跳轉到下一個人,否則用set的count函式判斷當前人的行李是否在行李轉盤上,如果在,則把他的行李從行李轉盤上刪去(使用erase函式完成),同時從行李佇列中取出隊頭填入到行李轉盤中,然後繼續下一個人;如果不在行李轉盤上,則把這個人重新入隊,繼續下一個人。直到人的佇列為空,記錄時間即可。
AC程式碼
#include<bits/stdc++.h>
// #include<Windows.h>
using namespace std;
int main()
{
cin.tie(0) -> sync_with_stdio(0);
int n, m;
cin >> n >> m;
queue<string> luggage; //行李的佇列
map<string, int> has;
for(int i = 0; i < n; i ++)
{
string s;
cin >> s;
luggage.push(s); // 按順序入隊每個行李
has[s] = 1; // 記錄當前行李出現過
}
queue<string> q; // 乘客的佇列
for(int i = 0; i < n; i ++)
{
string s;
cin >> s;
q.push(s);
}
set<string> now; // 行李轉盤
int ans = 0;
while(m-- && luggage.size()) // 首先取m件行李放入轉盤
{
now.insert(luggage.front());
luggage.pop();
}
while(q.size())
{
ans++; // 每次操作時間+1
string t = q.front(); // 取出乘客隊頭
q.pop();
if(!has[t]) // 如果這位乘客的行李沒有出現過說明丟失了
{
cout << t << " is lost!\n";
continue; // 直接下一步
}
if(!now.count(t)) q.push(t); // 如果行李不在轉盤,則重新入隊
else //在行李轉盤上
{
now.erase(t); // 從行李轉盤上刪去這件行李
if(luggage.size()) // 從行李佇列中補充一件行李到轉盤上
{
now.insert(luggage.front());
luggage.pop();
}
}
}
// 輸出答案
cout << ans;
}
C. A-3 Finding Independent Set
題面描述
Given a simple undirected graph \(G=(V,E)\). An independent set of G is a set \(S⊆V\) such that no two members of \(S\) are connected by an edge in \(E\). Finding the maximum independent set of \(G\) is an NP-hard problem. Here you are supposed to implement a greedy hueristic to find a near-maximum independent set.
The algorithm works in the following way:
- Collect any one un-visited vertex v into \(S\).
- Delete all the vertices (and all the edges incident on them) that are adjacent to \(v\) from \(G\).
- Repeat steps 1 and 2 until there is no un-visited vertex left in \(G\).
In order to obtain the unique solution, when there are many options in step 1, you must always choose the vertex with the smallest index.
輸入
Each input file contains one test case. For each case, the first line contains 2 positive integers: n (≤1000), the number of vertices; and m, the number of edges. Then m lines follow, each gives indices of the two ends of an edge. The vertices are indexed from 1 to n.
輸出
Print in a line the indices of the vertices in the independent set obtained by the given greedy algorithm. The indices must be in increasing order, and must be separated by exactly 1 space. There must be no extra space at the beginning or the end of the line.
樣例
in:
8 7
1 5
5 4
4 2
2 3
3 6
6 1
6 2
out:
1 2 7 8
題意簡述
給定一張圖,按順序求出一個獨立集,每次選擇一個點,刪除所有與這個點相鄰的點,直到沒有點可刪除,輸出這個獨立集。
獨立集: 圖中任意兩點之間沒有邊相連的子圖,或者說,選定一個集合,使得與集合中的點相鄰的點不在集合中。
題意簡述2
給定一張圖,求出字典序最小的獨立集
思路
按順序選擇一個點,如果這個點沒有被標記,就將他加入到答案序列中,並且標記他所有的相鄰點,如果被標記過則直接跳過。
AC程式碼
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
vector<int> edge[N];
int main()
{
int n,m;
cin >> n >> m;
while(m --)
{
int a,b;
cin >>a >>b;
edge[a].push_back(b);
edge[b].push_back(a);
}
vector<int> vis(n + 1), ans;
for(int i = 1; i <= n; i ++)
{
if(vis[i]) continue;
vis[i] = 1;
ans.push_back(i);
for(auto v : edge[i]) vis[v] = 1;
}
for(int i = 0; i < ans.size(); i ++)
cout << ans[i] <<" \n"[ans.size() - 1 == i];
}
D. A-4 The Smallest Open Interval
題面描述
Given a set \(S\) of points on the \(x\)-axis. For any point \(p\), you are suppose to find the smallest open interval that contains \(p\), provided that the two ends of the interval must be in \(S\).
輸入
Each input file contains one test case. Each case consists of several lines of commands, where each command is given in the format:
cmd num
where cmd is either I for "insert", or Q for "query", or E for "end"; and num is an integer coordinate of a point on the x-axis. It is guaranteed that num is in the range \([−10^9, 10^9]\).
The input is ended by E. It is guaranteed that there are no more than \(10^5\) distinct points in \(S\), and so is the number of queries. The total number of commands (E not included) is no more than \(3×10^5\).
輸出
For each I case, insert num into \(S\). For each \(Q\) case, output the smallest open interval that contains num in the format \((s1, s2)\), where both \(s_1\) and \(s_2\) must be in \(S\). On the other hand, if num is no larger than the smallest point in \(S\), s1 shall be replaced by \(-inf\), representing negative infinity; or if num is no smaller than the largest point in \(S\), \(s_2\) shall be replaced by \(+inf\), representing positive infinity.
It is guaranteed that there must be at least 1 point in S before the first query.
樣例
in:
I 100
Q 100
I 0
I 33
I -200
Q 25
Q 33
Q -200
Q 200
E
out:
(-inf, +inf)
(0, 33)
(0, 100)
(-inf, 0)
(100, +inf)
題意簡述
給定一個數軸上的點集,每次插入一個點,或者查詢一個點,輸出包含這個點的最小開區間。
題意簡述2
維護一個平衡搜尋樹,支援插入和查詢前驅後繼點(不存在則輸出+-inf)
思路
使用直接用C++的set容器維護即可
AC程式碼
#include<bits/stdc++.h>
using namespace std;
int main()
{
set<int> tr;
string op;
while(cin >> op, op != "E")
{
int p;
cin >>p;
if(op == "I") tr.insert(p);
else
{
if(tr.size() == 0)
{
cout << "(-inf, +inf)\n";
continue;
}
auto next = tr.upper_bound(p);
auto pre = tr.lower_bound(p);
--pre;
if(*pre >= p)
cout << "(-inf,";
else
{
cout << "(" << *pre << ",";
}
if(next == tr.end())
cout << " +inf)\n";
else cout << " " << *next <<")\n";
}
}
}