記錄2021.9.12
終於考完了。92分,已經超出了我自己的預期成績了,很開心。(弱弱的說,我考試前做PAT前幾年的仿真模擬卷都沒有上70的,最高60多分,雖然說這次應該算是這幾年以來最簡單的一次了吧,所以說考試前其實我是沒啥信心的QAQ,可能對於大佬來說92僅此而已,但是對我來說是莫大的驚喜了,開始沒幾分鍾點進去,就有大佬已經AC了,瑟瑟發抖~~)
因為准備考研浙大才准備的PAT甲級考試,但是考試前剛剛聽說軟工免推的PAT成績不能抵機試了,所以這次考試壓力也沒有多大。
我是非科班出身的,只是大一的時候有上過C語言,C++的相關課程,但都是水過去的。所以基本上到了大三還是不會打代碼的小菜雞一枚,為了准備考PAT也在圖書館借了算法筆記,收藏了柳婼大神的博客,看了很多的經驗貼。我大概是七月中旬開始准備的,那時候拿這算法筆記啃,感覺剛開始還是很吃力的,一道排序題就可以難住我好幾個小時,后來漸漸上手后,特別是學習了第六章的C++中的STL容器,感覺好用的飛起,明明可以很輕松的寫代碼,之前一直都在用土本法。但是這也算是一種經歷吧,沒有土辦法一點點的寫過,就不知道STL容器有多好用。到了八月份的時候,算法筆記才啃了不到一半,其實有點慌張了,大概是從八月中旬開始,就把每天大部分的時間往PAT上傾斜,emmm...大家不要學我,能盡早開始就不要偷懶,我就是懶慣了,才導致后面時間來不及。大概是到9月份初的時候,其實我才把算法筆記學習完,當然動態規划,后面字符串提升什么的沒學,畢竟沒時間了嘛,然后我就開始從后往前刷題庫,四道題四道題刷,看柳婼大神的代碼,但是由於柳婼大神的代碼是只有分析的,雖然講的很簡介明了,但是一般對於我們這種代碼打的少的人來說,其實不太容易想得到,所以我是把b站的講PAT甲級的up主弄夫的視頻和柳婼大神的代碼結合着學習的,從中其實也學習到了非常多STL容器的具體用法,其實算法筆記中雖然是講的較為詳細了,但是你用的太少還是不會用的,我覺得看別人的代碼看多了,自己自然而然的就用上了這些好用的方法,而不是糾結着一定要用自己寫出來的,我覺得就9月初一直到考試前,我自己結合大神的代碼視頻刷題學習的過程是我提升最快的時候,算法筆記只是給了你一個門檻,讓你懂得了該如何應對PAT上不同的題目,學習了各種算法(我真的是小白,之前從來沒用過這些算法)真的如大佬所言,就算是對於小白也是很友好的。不過想要有所提升,算法筆記明顯不夠用,在學習完算法筆記的基礎上,刷題總結學習大佬的代碼,思維方式才是備考的重中之重。
講一下這次考試的心路歷程,感覺看題是杠杠的重要的。剛開始做題的時候,我把所有的題目都看了一遍,大概看了一下要考啥,因為是英語(我的英語真一般,稍微來一點不常見的單詞就會不認識)所以讀題較慢。大概4道題讀了10分鍾,而且是粗粗的讀,根本沒有讀懂,就大概感覺第一題讀不懂,第二題好像考棧,第三題考圖論,第四題考堆?樹(剛開始是這樣想的),然后讀完題我就去看了一下提交通過率,好家伙,第一題的通過率低的離譜,反而是第四題最高,然后我就轉向第四題的懷抱了,但是讀了半天,也讀不懂題目,又是堆啊,又是中序遍歷啥的,然后我就想,難道和之前的一樣是考建堆嗎,只不過這個是小頂堆,然后我就按照堆的思路做下去(考前打過好幾遍相關代碼了,所以還是挺熟的),然后寫到向上調整的時候發現,好像我看到那張樣例圖給的不是完全二叉樹啊,這咋整,然后給我整愣住了,我又看了一下題目,發現沒啥思路。
這時候大概還有2個半小時,然后我就又去看了一下通過率,咋第二題的通過率這么高呢?我之前粗粗的看了一下第二題,其實也沒讀懂題目,然后我就去在仔細讀了一遍題目,發現的真的挺簡單的,只要稍微排序一下,然后用STL中的stack容器每次壓出一個帽子的size(我用的是unordered-map的兩個映射)就在映射中找到體重對應的位置下標輸出即可。很快20分鍾不到讀題和做題就結束了,這時候還有2個小時十幾分鍾,然后我就想好歹20分了,沒有被0封,心情不錯,就又去看通過率(呵呵,沒錯我就是看通過率做題的,其實效果還不錯,但是其實並不是通過率低的題目就一定難的,我我最后寫第一題的時候也就不到半個小時,通過率低說不定是里面有坑,所以很多大佬沒有拿到滿分),發現還是第四題較高,又跑去攻克第四題。這次仔細看了一下他給我的例子,那個pair,和圖,發現根據小的數字的堆頂就是小頂堆的特性,但是看他給出的好像key的順序好像是從小到大的,又看圖,發現很像題庫中做的一道建立笛卡爾樹的題目(就是每次從中序中選擇最小的數作為根節點,依據這個來建樹,這道題我考試前因為在背代碼段,所以也打過好幾遍了),所以發現這根本不是建堆,他只是有一點堆的特性,所以只需要把這個key和priority作為一個結構體一起排序,當然是按照key的值的從小到大排序了,然后把他們看成一個整體,每次在結構體數組中找到priority最小的值,然后然這個值作為根結點,遞歸建樹,最后層序遍歷一下就okk啦~,寫法之后一步AC,很開心。(現在看了一下覺得priority這個單詞好眼熟,想起了priority_queue所以這道題優先隊列應該更好做)
這時候大概還有1個小時30多分鍾,我就想,就剩兩題了,還能給我難住不成,然后我就開始做第三題,畢竟第一題通過率很低,而且我之前看了題目,確實不太讀的懂(提示沒看),看了之后,也是很快有了思路,大概意思就是給你一張圖,讓你選擇從哪個頂點出發可以遍歷到最多的頂點(訪問過的頂點不能再訪問),雖然我后來看到有人的群里說每次要選擇編號最小的點走,但是很奇怪的是,我由於沒有看到這句話,所以就是用了個dfs,進行深度遍歷,記錄遍歷的深度(即過一個頂點要讓深度+1,當然要回溯的,回來之后還要-1)直到沒有頂點可以走的時候就退出循環,哎,也是我太蠢了,沒有真正搞懂遞歸,雖然想法很簡單,但是現實很骨感啊,我發現無論我怎么做,我都導不出最后到達遞歸邊界的時候我想要的深度值,然后我就想debug吧,看一下出了什么問題,然后遇到了最讓我奔潰的事情,那個考點的Dev-C++是沒有辦法debug的,啊真想當場哭出來,由於我的電腦上之前也試過VS,但是不知道咋的就是用不了VS來運行C,所以我用的都是Dev-C,讓我當場去研究VS也不現實,那我只能cout打印看情況了呀,但是有錯的地方又在遞歸函數內部,搞的我頭暈,我后來就發現了,好像是因為函數內部的參數是個復制的參數,改變不了主函數的參數值的,然后我就想,有啥大不了的,用引用類型唄,然后發現不得行,報錯(也可能是我寫的有問題),然后我就想,這樣也不行那就全局變量,然后發現,全局變量也不得行,因為我寫的dfs是有回溯的,每次回溯回來就回到原值了,根本帶回不了最深層的深度的值,經過一次次的嘗試和失敗,我突然想起了之前在算法筆記上,用Dijkstra+DFS求最優解的時候,算法筆記上教我們的是在最深層的時候(就是到達遞歸邊界的時候)把想要的最大值賦值給全局變量,就可以帶回這個值了,然后我就這樣做了一下,果然AC了。(但是由於我是沒有看到其他大佬說的那句每次選擇往最小的點走的,所以我也還不太清楚為什么對),這時候由於在第三題耗費了太多時間了,沒有debug嗚嗚嗚,可惡。
第一題只剩下30分鍾了,我再次強調讀題真的很重要,讀好題目事半功倍,我讀題大概讀了15分鍾,才搞懂什么意思,(也是剛看時看題目的時候沒有看到下面的提示,耗費了幾分鍾的時間),然后就剩10多分鍾了,我就着急的,代碼打的很快,不到五分鍾就大概打好了,當然中間有些錯誤,因為沒有想太多就打了,根本沒時間,所以沒有想到什么方法就用了什么。中間改錯cout查看了一下,然后最后一分鍾改出來12分。這里說一下,由於我之前太急了,其實感覺這道題能過的希望也不大,所以我設數組設置了一個100大小的數組,所以雖然最后過了,但是從第三個點開始就段錯誤了,段錯誤的很明顯,誰叫我之前着急,設置了100大小的數組呢,哎,當然說這些為時已晚了。
這僅僅是我的一次考試體驗,以此記錄。當然覺得自己挺幸運的,碰上的這次考試這么簡單,不像前幾次的卷子,我看到題目沒有絲毫的想法。順便膜拜一下大佬們,TQL。
代碼
- 7-1 Arrays and Linked Lists (20 分)
Let's design a data structure A that combines arrays and linked lists as the following:
At the very beginning, an integer array A0 of length L0 is initialized for the user. When the user tries to access the i
th element A[i
], if 0≤i
<L0, then A[i
] is just A0[i
]. Now our system is supposed to return h0+i
×sizeof(int
)as the accessed address, where h0 is the initial address of A0, and sizeof(int
) is the size of the array element, which is simply int
, taking 4 bytes.
In case there is an overflow of the user's access (that is, i≥L0), our system will declare another array A1 of length L1. Now A[i
] corresponds to A1[j
] (It's your job to figure out the relationship between i and j). If 0≤j<L1, then h1+j×sizeof(int) is returned as the accessed address, where h1 is the initial address of A1.
And if there is yet another overflow of the user's access to A1[j], our system will declare another array A2 of length L2, and so on so forth.
Your job is to implement this data structure and to return the address of any access.
Input Specification:
Each input file contains one test case. For each case, the first line gives 2 positive integers N (≤104) and K (≤103) which are the number of arrays that can be used, and the number of user queries, respectively.
Then N lines follow, each gives 2 positive integers, which are the initial address (≤107) and the length (≤100) of an array, respectively. The numbers are separated by spaces. It is guaranteed that there is no overlap of the spaces occupied by these arrays.
Finally, K indices of the elements queried by users are given in the last line. Each index is an integer in the range [0,220].
Output Specification:
For each query, print in a line the accessed address. If the queried index exceeds the range of all the N arrays, output Illegal Access
instead, and this query must NOT be processed.
Print in the last line the total number of arrays that have been declared for the whole process.
Sample Input:
6 7
2048 5
128 6
4016 10
1024 7
3072 12
9332 10
2 12 25 50 28 8 39
Sample Output:
2056
4020
1040
Illegal Access
3072
140
3116
5
Hint:
A[2] is just A0[2], so the accessed address is 2048+2×4=2056.
In order to access A[12], declaring A1 is not enough, we need A2 with initial address h2=4016. Since A[12]=A2[1], the accessed address is 4016+1×4=4020.
In order to access A[25], we need A3 with initial address h3=1024. Since A[25]=A3[4], the accessed address is 1024+4×4=1040.
The access of A[50] exceeds the maximum boundary of all the arrays, and hence an illegal access. There is no extra array declared.
In order to access A[28], we need A4 with initial address h4=3072. Since A[28]=A4[0], the accessed address is just 3072.
It is clear to see that A[8]=A1[3] and hence the accessed address is 128+3×4=140; and A[39]=A4[11] so the accessed address is 3072+11×4=3116.
All together there are 5 arrays used for the above queries.
考試時候的代碼,只拿了12f,如果不是數組太小段錯誤的話,就有18f了,其中一個是答案錯誤,倒是第二個點錯誤,暫時還沒找到
#include<iostream>
#include<cctype>
#include<string>
#include<set>
#include<stack>
#include<unordered_set>
#include<unordered_map>
#include<map>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
int main(){
int n,m;
cin >> n >> m;
int a[100],len[100];
for(int i = 0; i < n; i++){
cin >> a[i] >> len[i];
}
int sum = 0;
int c[100];
for(int i = 0; i < n; i++){
sum += len[i];
c[i] = sum;
}
int maxn = -1;
while(m--){
int b;
cin >> b;
if(b>=c[n-1]) cout<<"Illegal Access" <<endl;
else{
int i;
for( i = 0; i < n; i++){
if(c[i]>b) break;
}
if(b>maxn){
maxn = b;
}
if(i==0)cout << a[i] + 4 * b<<endl;
if(i!=0)cout << a[i] + 4 *(b-c[i-1])<<endl;
}
}
int i;
for(i = 0; i < n; i++){
if(c[i]>=maxn) break;
}
cout << i+1;
return 0;
}
7-2 Stack of Hats (25 分)
PATers believe that wearing hats makes them look handsome, so wherever they go, everyone of them would wear a hat. One day they came to a restaurant, a waiter collected their hats and piled them up. But then when they were ready to leave, they had to face a stack of hats as shown by the above figure. So your job is to help them line up so that everyone can pick up his/her hat one by one in order without any trouble.
It is known that every hat has a unique size, which is related to the weight of its owner -- that is, the heavier one wears larger hat.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive number N (≤104) which is the number of PATers. The next line gives N distinct sizes of the hats, which are positive numbers no more than 105. The sizes correspond to the hats from bottom up on the stack. Finally in the last line, N distinct weights are given, correspond to the hat owners numbered from 1 to N. The weights are positive numbers no more than 106. All the numbers in a line are separated by spaces.
Output Specification:
For each test case, print in a line the indices of the hat owners in the order of picking up their hats. All the numbers must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
Sample Input:
10
12 19 13 11 15 18 17 14 16 20
67 90 180 98 87 105 76 88 150 124
Sample Output:
3 4 8 6 10 2 1 5 9 7
Hint:
The 1st hat has the largest size 20, hence must correspond to the one with the largest weight, which is the 3rd one of weight 180. So No.3 must go first.
The 2nd hat has the 6th smallest size 16, hence corresponds to the 6th smallest weight, which is 98. So No.4 is the next to go.
And so on so forth.
代碼
#include<iostream>
#include<stack>
#include<unordered_map>
#include<algorithm>
using namespace std;
const int maxn = 10001;
int weight[maxn];
int hat[maxn];
bool cmp(int a,int b){
return a > b;
}
int main(){
int n, si, ans = 0;
cin >> n;
unordered_map<int,int> ind, hat_to_weight, weight_to_hat;
stack<int> st;
for(int i = 0; i < n; i++){
scanf("%d",&si);
hat[i]=si;
st.push(si);
}
for(int i = 0; i < n; i++){
scanf("%d",&weight[i]);
ind[weight[i]]= i + 1;//有體重得到下表
}
sort(weight,weight+n,cmp);
sort(hat,hat+n,cmp);
for(int i = 0; i < n; i++){
hat_to_weight[hat[i]]=weight[i];
weight_to_hat[weight[i]]=hat[i];
}
while(!st.empty()){
int nowsize = st.top();
st.pop();
int num = ind[hat_to_weight[nowsize]];
if(ans) cout << ' ';
cout << num;
ans++;
}
return 0;
}
7-3 Playground Exploration (25 分)
A playground is equipped with ball pits and tents connected by tunnels. Kids can crawl through the tunnels to meet their friends at a spot with a tent or a ball pit.
Now let's mark each meeting spot (a tent or a ball pit) by a number. Assume that once a kid starts to explore the playground from any meeting spot, he/she will always choose the next destination with the smallest number, and he/she would never want to visit the same spot twice. Your job is to help the kids to find the best starting spot so they can explore as many spots as they can.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (≤100), the total number of spots, and M, the number of tunnels. Then M lines follow, each describes a tunnel by giving the indices of the spots (from 1 to N) at the two ends.
Output Specification:
Print in a line the best starting spot which leads to the maximum number of spots, and the number of spots a kid can explore. If the solution is not unique, output the one with the smallest index. There must be exactly 1 space between the two numbers, and there must be no extra space at the beginning or the end of the line.
Sample Input:
8 10
1 2
3 4
5 8
1 4
6 1
3 7
2 4
5 3
2 8
2 5
Sample Output:
6 7
Hint:
Actually there are two solutions. Kids can either start from 6 and go through 1->2->4->3->5->8, or from 7 to 3->4->1->2->5->8, both can visit 7 spots. Since 6 is a smaller index, we output 6 as the starting spot.
代碼
#include<iostream>
#include<set>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 101;
const int INF = 1000000000;
int G[maxn][maxn];
int n, m;
bool vis[maxn] = {false};
//從一點開始,走過的點要盡可能的多,而且訪問過的節點就不能在訪問了,求訪問能夠走到最多的點的起點的下表,並且求出能最多走多少個點,如果路徑不唯一,就要走下表最小的那個
int maxdepth = -1;
bool if_can_vis_other(int x){//判斷當前結點是否還存在可以繼續訪問的結點
for(int i = 1; i <= n; i++){
if(G[i][x]!=INF&&vis[i]==false) return true;
}
return false;
}
int mdepth = -1;
void dfs(int index,int depth){
if(if_can_vis_other(index)==false){//已經沒有結點可以繼續訪問了
if(depth>mdepth){
mdepth = depth;
}
return;
}
vis[index]=true;
for(int i = 1; i <= n; i++){
if(vis[i]==false&&G[i][index]!=INF){
dfs(i,depth+1);
}
}
}
int main(){
scanf("%d%d",&n,&m);
fill(G[0],G[0]+maxn*maxn,INF);
for(int i = 0; i < m; i++){
int t1,t2;
scanf("%d%d",&t1,&t2);
G[t1][t2] = G[t2][t1]=1;
}
int maxdepth = -1;
set<int> loc;
for(int i = 1; i <= n; i++){//對於每一個起點,我們都遍歷一下,找到數量最大的那個就好了
memset(vis,false,sizeof(vis));//每一個都要重新初始化
vis[i]=true;
mdepth = -1;
dfs(i,1);
if(mdepth>maxdepth){
maxdepth = mdepth;
loc.clear();//如果這個值比最大值還要大更新最大值,並且清空最大值所對應的起點的下標
loc.insert(i);//存入當前地址的下標
}else if(mdepth==maxdepth){
loc.insert(i);//如果最大值一樣,都存在set里面,自動排序,最小的就在前面
}
}
auto it = loc.begin();
printf("%d %d",*it,maxdepth);
return 0;
}
7-4 Sorted Cartesian Tree (30 分)
A Sorted Cartesian tree is a tree of (key, priority) pairs. The tree is heap-ordered according to the priority values, and an inorder traversal gives the keys in sorted order. For example, given the pairs { (55, 8), (58, 15), (62, 3), (73, 4), (85, 1), (88, 5), (90, 12), (95, 10), (96, 18), (98, 6) }, the increasing min-heap Cartesian tree is shown by the figure.
Your job is to do level-order traversals on an increasing min-heap Cartesian tree.
Input Specification:
Each input file contains one test case. Each case starts from giving a positive integer N (≤30), and then N lines follow, each gives a pair in the format key priority
. All the numbers are in the range of int.
Output Specification:
For each test case, print in the first line the level-order traversal key sequence and then in the next line the level-order traversal priority sequence of the min-heap Cartesian tree.
All the numbers in a line must be separated by exactly one space, and there must be no extra space at the beginning or the end of the line.
Sample Input:
10
88 5
58 15
95 10
62 3
55 8
98 6
85 1
90 12
96 18
73 4
Sample Output:
85 62 88 55 73 98 58 95 90 96
1 3 5 8 4 6 15 10 12 18
代碼
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int INF = 1000000000;
struct node{
int key, priority;
node* lchild,*rchild;
};
struct p{
int key, priority;
}p[31];
bool cmp(struct p a,struct p b){
return a.key < b.key;
}
node* creat(int inL,int inR){
if(inL > inR) return NULL;
int k, MIN = INF;
for(int i = inL; i <= inR; i++){
if(p[i].priority < MIN){
MIN = p[i].priority;
k = i;
}
}
node *root = new node;
root->priority = MIN;
root->key = p[k].key;
root->lchild = creat(inL, k - 1);
root->rchild = creat(k + 1, inR);
return root;
}
vector<int> k, pr;
void leverOrder(node* root){
queue<node*> q;
q.push(root);
while(!q.empty()){
node* cur = q.front();
q.pop();
k.push_back(cur->key);
pr.push_back(cur->priority);
if(cur->lchild!=NULL) q.push(cur->lchild);
if(cur->rchild!=NULL) q.push(cur->rchild);
}
}
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++){
cin >> p[i].key >> p[i].priority;
}
sort(p,p + n,cmp);
node* root = creat(0, n-1);
leverOrder(root);
for(int i = 0; i < k.size();i++){
if(i) printf(" ");
printf("%d",k[i]);
}
printf("\n");
for(int i = 0; i < pr.size();i++){
if(i) printf(" ");
printf("%d",pr[i]);
}
return 0;
}