2021-09-12 秋季PAT甲级满分总结

1.考前准备

我的考试准备经历可能比较特别,今年3月份花了1个月在MOOC看了翁老师的C语言课以及浙大的数据结构与算法分析课程,之前的基础就是大一学过C语言课,如今已经毕业一年了,浙大的数据结构网课是纯用C实现的,所以做起题来比较繁琐,像队列堆栈这种简单的线性结构也要自己实现,不过好处也是很明显的,手动实现多了就会对数据结构有更深的了解,也算是打下了比较好的基础吧。

网课看到哈希映射那里就没继续了,因为4月份有一些工作上的事情,结果这一搁置就到了9月份(对),我本来报名只是想参与一下,9月初甚至还想退款但是发现报名截止前几天不接受退款了,于是赶紧买了算法笔记和上机实战指南,等快递的时间把浙大网课哈希映射的部分看完了,大概4号书到了就开始补STL容器部分,从这时候开始练习用C++做题。

4号到10号基本就是在看书,题都没时间做,把以前的笔记拿出来配合算法笔记一起重温,发现浙大的网课内容还是有一点不足的,比如普通树的存储,最短路的dilkstra + DFS就没讲;但是算法笔记一些内容也没有网课讲的明白,像dilkstra还是陈老师直接演示比较直观,一下就明白了,光看文字确实太枯涩了。

看书一直持续到11号早上,11号下午就是考试时间了,说实话我心里还是很虚的,因为基本上就没怎么刷题,3月份上网课的时候会去做课后的作业,难度其实和PAT甲级一样,网课的内容十分精炼,上几十分钟网课就要去做PAT练习,可想而知有多困难,那时候一道题卡一天是很正常的事情,9月份以来代码量主要集中在测试上,比如动手实现一下STL容器和相关算法,或者自己建一棵树遍历一下,考完试看了一下PTA网站的做题量,PAT难度的题只有25道,还是3月份做的。

2.考试经历(附代码)

2.1第一题

#include <cstdio>
using namespace std;

typedef struct Node ar;
struct Node {
	int adr;
	int num;
};

int main() {
	int arrNum, queries, idxSum = 0, len = 0, idx, decNum = 1;
	scanf("%d%d", &arrNum, &queries);
	ar t[arrNum];
	for (int i = 0; i < arrNum; i++) {
		scanf("%d %d", &t[i].adr, &t[i].num);
		len += t[i].num;
//		printf("len = %d\n", len);
	}
	for (int i = 0; i < queries; i++) {
		scanf("%d", &idx);
//		printf("%d ", idx);
		if (idx >= len) {
			printf("Illegal Access\n");
		} else {
			int j = 0, tmpNum = 1;
			while (idx >= t[j].num) {
				idx -= t[j].num;
				tmpNum++;
				j++;
			}
			if (tmpNum > decNum) decNum = tmpNum;
			printf("%d\n", t[j].adr + idx*sizeof(int));
		}
		
	}
	printf("%d", decNum);
	return 0;
}

题目忘记摘了,等真题出来以后大家再自己对着看吧,题目大意其实就是把一个数组分成n段,每段有自己的初始地址和长度,比如第1段A1从1024开始,长度为5;第2段A2从2048开始,长度为4;那么给出一个下标7,则A[7] = A2【2】 = 2048 + 2 * sizeof(int) = 2056;
是不是很简单?但是原题真的很难读,我第一时间根本没明白是啥意思,这题花了大概五十多分钟,可以说是开门不顺了,后来做完以后,发现这题的通过率是最低的,我感觉难度主要在理解题意上了。

2.2第二题

#include <cstdio>
#include <stack>
#include <algorithm>
#include <map>
using namespace std;

bool cmp(int a, int b) {
	return a > b;
}

struct Node {
	int Weight;
	int Idx;
};

bool cmpw(struct Node a, struct Node b) {
	return a.Weight > b.Weight;
}

int main() {
	int Num;
	scanf("%d", &Num);
	int Hat[Num];
	struct Node W[Num];
	int tmpH[Num];
	stack<int> H;
	for (int i = 0; i < Num; i++) {
		scanf("%d", &Hat[i]);
		tmpH[i] = Hat[i];
//		H.push(tmpH);
	}
//	printf("%d\n", H.size());
	sort(Hat, Hat + Num, cmp);
	map<int, int> HatMap;
	for (int i = 0; i < Num; i++) {
		HatMap[Hat[i]] = i;
	}
	
	for (int i = 0; i < Num; i++) {
		scanf("%d", &W[i].Weight);
		W[i].Idx = i + 1;
	}
	sort(W, W + Num, cmpw);
	int check = 1;
	for (int i = Num - 1; i >= 0; i--) {
//		int tmp = H.top();
//		H.pop();
//		printf("%d ", tmpH[i]);
		if (check) {
			printf("%d", W[HatMap[tmpH[i]]].Idx);
			check = 0;
		} else {
			printf(" %d", W[HatMap[tmpH[i]]].Idx);	
		}
		
	}
	
	return 0;
}

题意:给一个N,然后第二行给N个帽子的Size(以压入堆栈的形式), 第三行给N个人的体重(序号从1到N);体重越大的人戴越大的帽子,然后让你输出拿帽子的顺序,就是把第二行的数据一个个弹出堆栈,然后匹配相应的体重,输出那个人的序号;N的数值大概是10的5次方还是6次方,我给忘了。
说实话这题我没想到什么巧妙的方法,当时的思路就是先读入帽子Size,存到堆栈和一个数组里,对数组排序以后用map映射到0、1、2、3这些序号上;体重的话把序号和体重绑在一起存进数组,然后按体重排序,最后弹出一个帽子Size --> 序号 -->体重数组下标,然后输出下标.序号。
这题写完只剩一个半小时了,因为中途出了点小问题,用stack容器存第二行数据不知道为什么只能存一半,排查了一会才发现,最后临时用一个数组代替stack。

2.3第三题

#include <cstdio>
#include <stack>
#include <algorithm>
#include <map>
using namespace std;

#define MaxVNum 110
#define Null -1
int Nv, Ne;
int G[MaxVNum][MaxVNum];
int Visit[MaxVNum] = {false};
int MaxSpotNum = 0;
void DFS(int V, int spotNum) {
	Visit[V] = true;
	if (spotNum > MaxSpotNum) {
		MaxSpotNum = spotNum;
	}
	for (int i = 1; i <= Nv; i++) {
		if (!Visit[i] && G[V][i] != Null) {
			DFS(i, spotNum + 1);
		}
	}
}

void Init() {
	for (int i = 0; i <= Nv; i++) {
		Visit[i] = false;
	}
}

int main() {
	int v1, v2, V;
	scanf("%d%d", &Nv, &Ne);
	for (int i = 1; i <= Nv; i++) {
		for (int j = 1; j <= Nv; j++) {
			G[i][j] = Null;
		}
	}
	for (int i = 1; i <= Ne; i++) {
		scanf("%d%d", &v1, &v2);
		G[v1][v2] = G[v2][v1] = 1;
	}
	for (int i = 1; i <= Nv; i++) {
		int CurSpotNum = MaxSpotNum;
		DFS(i, 1);
		Init();
		if (CurSpotNum != MaxSpotNum) {
			V = i;
			CurSpotNum = MaxSpotNum;
		}
	}
	
	printf("%d %d", V, MaxSpotNum);
	return 0;
}

非常简单的DFS,今年的图题应该算特别简单了,一个无向无权图的DFS,问从哪个顶点DFS能访问最多的顶点,输出该顶点以及访问最多的顶点数。
有两个条件,一个是优先从顶点编号最小的开始访问,另一个是同一个顶点不会访问两次,前者其实就是DFS的时候从1到N还是从N到1的问题,但是按照惯例大家都是从1到N遍历的,所以基本上相当于无条件,后者用一个Visit数组记录每个顶点是否被访问过就可以;最后每个顶点用一次DFS,记录最大访问数即可。

2.4第四题

//第四题
#include <cstdio>
#include <stack>
#include <algorithm>
#include <map>
#include <queue>
using namespace std;

typedef struct Node Nd;
struct Node {
	int P;
	int Val;
};

bool cmp(Nd a, Nd b) {
	return a.P < b.P;
}

typedef struct TNode *BinTree;
struct TNode {
	Nd data;
	BinTree Left;
	BinTree Right;
};

void Insert(BinTree &T, Nd X) {
	if (!T) {
		T = new TNode;
		T->data = X;
		T->Left = T->Right = NULL;
		return;
	}
	if (T->data.Val > X.Val) {
		Insert(T->Left, X);
	} else if (T->data.Val < X.Val){
		Insert(T->Right, X);
	}
} 

void LayerOrder(BinTree T) {
	queue<BinTree> q;
	q.push(T);
	int check  = 1;
	while (!q.empty()) {
		BinTree tmp = q.front();
		q.pop();
		if (check) {
			printf("%d", tmp->data.Val);
			check = 0;	
		} else {
			printf(" %d", tmp->data.Val);
		}
		
		if (tmp->Left) q.push(tmp->Left);
		if (tmp->Right) q.push(tmp->Right);
	}
	printf("\n");
	q.push(T);
	check  = 1;
	while (!q.empty()) {
		BinTree tmp = q.front();
		q.pop();
		if (check) {
			printf("%d", tmp->data.P);
			check = 0;
		} else {
			printf(" %d", tmp->data.P);
		}
		
		if (tmp->Left) q.push(tmp->Left);
		if (tmp->Right) q.push(tmp->Right);
	}
}

int main() {
	int N;
	scanf("%d", &N);
	Nd t[N];
	for (int i = 0; i < N; i++) {
		scanf("%d %d", &t[i].Val, &t[i].P);
	}
	sort(t, t+N, cmp);
	BinTree T = new TNode;
	T->Left = T->Right = NULL;
	T->data = t[0];
	for (int i = 1; i < N; i++) {
		Insert(T, t[i]);
	}
	LayerOrder(T);
	return 0;
}

说实话这题我一开始也没看懂,做到这一题的时候还剩一个小时,题目大概说的是有一种树,结点是一个结构体,包括值和优先级,给出N个结点,让你自己建树然后输出层序遍历结果,第一行输出值,第二行输出优先级。可见题目唯一难度在于如何建树。
题目里还用到了heapSort这种词,我一开始以为是堆排序,看了一下好像也没关系,因为题目里面示例建出来的树也不是一棵完全二叉树,就这样看了二十多分钟题目,也没有什么思路,出来看了一下这道题居然是通过率最高的,赶紧再回头看了下题目,试着往简单的方向去想,最后发现把数据按照优先级排好,然后按照二叉搜索树的插入方式就可以建出和示例一样的树。。。虽然不知道为什么,但是就这样去写了。
建树加层序遍历应该是最基本的东西了,写了不到十分钟写完了,层序遍历那里着急了直接复制粘贴遍历两次,一次输出值,一次输出优先级,结果一次就AC了,到最后也没明白这题啥意思,等以后大佬解答吧

3.总结和感想

21秋季的题应该算是比较简单了,第一次参加PAT,我感觉难度更多是在理解题意上面,理解题目以后这四道题都是一次AC了,都不用花时间测试和调试,结合自己的经验和经历给大家几个小建议吧

1、STL容器和algorithm头文件的一些算法(特别是sort)非常非常非常有用,不是说不会就写不出题目,但是会了能节省很多时间,能把精力集中在解决问题而不是编码上;
2、我个人建议是先看完浙大网课,同时把课后编程题做完(用C语言),再用算法笔记学习STL容器等应试的技巧,最后有时间再配合上机实战指南刷PAT(最后这一步我都没做),这些事情做完我相信在PAT甲级可以取得优良的成绩。

复习重点的话其实很多大佬总结过了,我这就做个小总结吧,当作参考
1、基本线性结构肯定要熟练,数组链表是实现各种数据结构的基础;
2、建树以及基本操作(插入删除等),尤其是二叉搜索树;时间紧张的话AVL和哈夫曼不看也行,但是堆的调整插入删除还是要理解的;
3、建图以及图的遍历,要结合树一起深刻理解DFS和BFS的思想及实现方法;最短路径Dilkstra配合DFS也要会,时间紧张的话最小生成树Prim之类的不看也行,其实写法和Dilkstra差不多。
4、理解映射的思想。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值