PAT甲级_2023夏_满分思路

总结

第二次参加PAT考试,这次考试意外简单,没有一题代码量是超过40行的。一个多小时AK,第二名。结果还没出来,但感觉这次满分会很多。以下是自己考试时的思路,觉得不错点个赞吧OvO。也欢迎大家一起讨论更优解~(比如最后一题我用了12MB,应该是有优化空间的)

题一

题意

这是一道模拟题,题目给出了一种贪心解法,要求咱们代码实现。
题意是给出一张n * n大小的图,图中每个元素或等于0、或等于1。0表示可以通行,1表示有障碍物。有n个机器人编号为1-n,他们遵循题目给的方法移动,从南方出发前往北方。但这种方法具有被困住的风险,要求升序输出按这种方法前进会被困住的机器人的编号。
这种方法是:

  • 如果北方一格没有障碍物,则朝北走;
  • 如果北方一格有障碍物,则尝试朝西走
    • 如果西方也有障碍物就说明不能向北、也不能像西走,称之为trap,
    • 如果西方没有障碍物则向西走一格后再尝试向北走
      注:可以走出给的这张图:即假设图中左侧格子纵坐标为1,则可以走到纵坐标为0的位置,而纵坐标为0的这一列是没有障碍的,机器人走到这一列,就可以一路向北到达北岸。

思路

  • 因为咱是从南岸出发到达北岸,且西侧可以走出图表,所以图表的横纵坐标分别从下标1开始记录。这样子西侧(0, 0) - (n + 1, 0)元素都等于0,就有了一条走出图表后一路向北的路线。然后元素分别从(n + 1, id)的南侧出发,前往北侧使得纵坐标为0。
  • 所以先记录图边长于变量int n
  • 然后设置一张图bool gra[105][105],进行填充。注意这里一行的元素之间是没有空格的,所以得用字符串string 记录一行的元素,然后挨个取出填入每行gra[i]中。
  • 下标i取从1到n,依次模拟每个机器人行走,初始位置为[n+1, i]
    • 每次循环首先判断是否到达北岸(while(x != 0))、然后判断北方是否有障碍物if(!gra[x - 1][y])
      • 如果没有障碍物,就朝北走一格
      • 如果有障碍物,就判断西方是否有障碍物
        • 如果西方也有障碍物,说明这个机器人被trap了
        • 如果西方没有障碍物,则一路西行,每次走一步判断:
          • 当前是否出了图表(y = 0),出了说明可以到达北岸,则直接令x = 0跳出循环。
          • 当前可以向北走了,朝北走一格,进行下一轮循环。
    • 出循环后看是否到达了北岸(if(x != 0))。没到北岸的说明trap,记入ans数组。
      最后依次输出ans数组元素。

题解

#include<bits/stdc++.h>
using namespace std;
int n;
bool gra[105][105];
string input;
vector<int> ans;
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++){
		cin>>input;
		for(int j = 1; j <= n; j ++)
			gra[i][j] = input[j - 1] - '0';
	}
	for(int i = 1; i <= n; i ++){
		int x = n + 1, y = i;
		while(x != 0){ //没到北岸 
			if(!gra[x - 1][y]){ //能向北走 
				x--;
				continue;
			}else if(gra[x - 1][y]){ // 不能向北走 
				if(gra[x][y - 1]) break; //也不能向西走,跳出循环,此时x一定不为0 
				while(!gra[x][y - 1]){ // 能向西走 
					y--;
					if(y == 0){ //向西走到纵坐标为0的位置则能成功到达南岸 
						x = 0;
						break;
					}
					if(!gra[x - 1][y]){ // 向西走后发现可以向北走了,就向北走一步。 
						x--;
						break;
					}
				}
			}
		}
		if(x != 0) ans.push_back(i);
	}
	for(int i = 0; i < ans.size(); i ++)
		printf("%d%c", ans[i], i == ans.size() - 1 ? '\n' : ' ');
	return 0;
} 

题二

题意

  • 有两个栈,记为a、b。
  • 给出操作次数n,然后依次进行如下两个操作:入栈I num、出栈O
    • 入栈时,num压入a的栈顶。
    • 出栈时,看b是否有元素。如果有元素,则栈顶元素出栈,输出元素值;如果b栈空,则把a中所有数据搬到b中,然后弹出栈顶元素,输出元素值;如果a也空,则输出ERROR。
  • 输出元素值的同时,还要输出出栈操作的时间。时间的定义如下:每次入栈、出栈都占1个单位的时间。

思路

  • 先记录操作次数于变量int n
  • 然后循环n次,每次操作码记入char op
    • 如果op == 'I',说明是入栈操作。记录入栈元素num,压入栈a中。
    • 否则就是出栈操作,判断b中是否有元素出栈。
      • 如果b中有元素,则弹出栈顶元素,耗时为1
      • 如果b中没有元素,则判断a中是否有元素
        • 如果a中有元素,则将a中元素依次弹出,压入b中,然后弹出b的栈顶元素,耗时为b.size() * 2 + 1
        • 如果a中没有元素,则说明没法弹出元素,输出ERROR

题解

#include<bits/stdc++.h>
using namespace std;
stack<int> a, b;
int n, num;
char op;
int main(){
	scanf("%d", &n);
	while(n--){
		getchar(); //解决换行符问题 
		scanf("%c", &op);
		if(op == 'I'){
			scanf("%d", &num);
			a.push(num);
		}else{
			if(b.size()){
				printf("%d 1\n", b.top());
				b.pop();
			}else{
				if(!a.size()) puts("ERROR");
				else{
					while(a.size()){
						int tmp = a.top();
						a.pop();
						b.push(tmp);
					}
					printf("%d %d\n", b.top(), b.size() * 2 + 1);
					b.pop();
				}
			}
		}
	}
	return 0;
} 

题三

题意

有一颗二叉树,给出结点个数n,然后给出树的中序遍历序列int in[31]和先序遍历序列int pre[31]。要求计算度分别为0、1、2的结点个数记为n0,n1,n2,然后计算出n1 * n2 / n0并按要求输出。

思路

  • 首先记录节点个数于变量int n
  • 然后分别用数组int in[30]``int pre[30]记录中序遍历序列和先序遍历序列。
  • 常规造树,每次造完树节点node*t后返回时,判断其左右子树非空个数,以此更新n0、n1、n2的结果。
  • 按要求输出。

题解

#include<bits/stdc++.h>
using namespace std;
int n, n0, n1, n2, pre[100], in[100];
struct node{
	struct node * l, * r;
};
node* mt(int il, int ir, int pl, int pr){
	if(il > ir) return NULL;
	node * t = (node*) malloc (sizeof(node));
	int i = il;
	while(in[i] != pre[pl]) i++;
	t->l = mt(il, i - 1, pl + 1, pl + i - il); //x - pl - 1 = i - 1 - il;
	t->r = mt(i + 1, ir, pl + i - il + 1, pr);
	if(t->l && t->r) n2++;
	else if(!t->l && !t->r) n0++;
	else n1++;
	return t;
}
int main(){
	scanf("%d", &n);
	for(int i = 0; i < n; i ++) scanf("%d", &in[i]);
	for(int i = 0; i < n; i ++) scanf("%d", &pre[i]);
	node* t = mt(0, n - 1, 0, n - 1);
	printf("%d * %d / %d = %d", n1, n2, n0, n1 * n2 / n0);
	return 0;
}

题四

题意

  • 要随机生成一个n位的长数字,有一种方法是准备n张卡片给n个孩子,卡片正面编号id从1-n,卡片反面由孩子从0-9中任取一个数字value填上去。然后把这n张卡片按正面编号id从1-n排序,反面的value组合就排列成了一个n位的长数字。
  • 但现在这n张卡片被打乱了,你不知道哪一面是正面记录着编号id,哪一面是反面记录着value。所以要求只要一侧排序为1-n即可,然后输出另一侧组成的n位长数字。如果答案不唯一,则输出最小的那种可能。

思路

  • 用rec数组记录卡片的id和value.
    • 由于不知道哪一面是正面,所以得正着记一次,反着记一次.
    • 同时为了避免一张卡片记两次,所以不妨以插入时间t为依据,给每张卡片编号
    • 用数组bool st[100100]以时间t为唯一tag记录这张卡片是否被使用过。
    • 所以一张卡片记录格式为pair<pair<int, int>,int>,即<<id, value>, t>,这么写是为了数据结构清晰,当然也可以写作int card[3]
  • 首先记录节点个数于变量int n
  • 然后循环n次,每次分别将卡片正向、反向插入rec数组。
  • sort一下rec数组,于是rec中元素首先按照id从小到大排列,有相同id的就以value从小到大排列,这样后续DFS找到的第一个n位数就是最小n位数,极大简化了寻找最小满足题意的n位数的步骤。
  • 最后DFS(int ptr_id, int ptr_rec)寻找最小(第一个)满足题意的n位数。
    • 第一个参数表示我现在要找id = ptr_id的卡片
    • 第二个参数表示我当前遍历到了数组中的第ptr_rec个元素。
    • 如果ptr_id = n + 1说明已经排序好了1-n个元素,于是就可以输出这个元素,然后一个bool型变量flag设置为true表示已经完成输出,此后递归都会直接跳出返回if(flag) return;
    • 每次查找都从下标ptr_rec开始往后查找,由于rec是按id升序排列的,所以目标一定在ptr_rec及之后,如果找到可用卡片,则设置卡片已使用st[rec[i].second] = true;,将卡片value插入输出数组,然后DFS(ptr_id + 1, i + 1)寻找下一目标id。

题解

#include<bits/stdc++.h>
using namespace std;
int n, a, b;
bool st[100100]; //对应于t 
vector<pair<pair<int, int>, int>> rec;//<<id, value>, t> 
vector<int> ans;
bool flag = false;
//以id顺序从1扫描到n,期望num最小,还需要记录卡片用过没有,所以用输入时间作为该卡片的另一属性,以避免重复使用 
void DFS(int ptr_id, int ptr_rec){
	//从rec数组从头到尾扫描,id是rec[i].first.first因为sort函数,所以也是升序排列的。
	//当前排列到第ptr_id个位置,扫描到ptr_rec,还没纳入需要 
	if(flag) return;
	if(ptr_id == n + 1){
		for(int i = 0; i < ans.size(); i ++) printf("%d", ans[i]);
		flag = true;
		return;
	}
	for(int i = ptr_rec; i < rec.size(); i ++){
		if(rec[i].first.first < ptr_id) continue;
		if(rec[i].first.first > ptr_id) break;
		if(st[rec[i].second]) continue;//用过了 
		st[rec[i].second] = true;
		ans.push_back(rec[i].first.second);
		DFS(ptr_id + 1, i + 1);
		ans.pop_back();
		st[rec[i].second] = false; 
	}
}
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++){
		scanf("%d %d", &a, &b);
		rec.push_back({{a, b}, i});
		rec.push_back({{b, a}, i});
	}
	sort(rec.begin(), rec.end());
	DFS(1, 0);
	return 0;
}

原题

A-1 Trap

A robot is designed to move on a map from South toward North. When some obstacle is encountered, the robot can only turn toward West and moves until it can turn toward North and continue.

Given a squared map with n×n blocks, a robot can start from any position below the bottom line (South) and its target is to reach the top line (North). (By the way, kindly remind you that the left-hand-side of the map is West and the right-hand-side is East.)

If some obstacles are placed in the map, the robot might get trapped if it starts from certain positions and can never reach the North line. For example, in the situation given by the following figure, the robot will be trapped if it starts from either position 7 or 8.

map.jpg

Your job is to point out those starting positions which will get the robot trapped.

Note: it is assumed that a robot can move out of the map boundary, and all the blocks around the map are open, without any obstacle. Hence if the robot starts from any position out of the West or East boundary, it can certainly reach North without any problem. Therefore we only have to consider the positions between the West and East boundaries (e.g. the positions from 1 to 10 below the South line in the above figure). Besides, as long as the robot can reach the North line, it is considered successful even of it ends up at out of the boundary (e.g. the robot will have to move out of the map if starts from either the positions 1 or 2, but it can still reach the North line).

Input Specification:

Each input file contains one test case. Each case starts from a positive integer n (≤100) in a line, which is the size of the map. Then n lines follow, each contains n characters, which are either 0 for an open block, or 1 for a block with obstacle. The first line corresponds to the North boundary and the last line the South.

Output Specification:

Output in a line all the starting positions which can get the robot trapped, in increasing order. The positions are indexed from West to East, starting from 1. It is guaranteed that there is at least one output.
All the numbers must be separated by 1 space, and there must be no extra space at the beginning or the end of the line.

Sample Input:

10
0000000000
0000111010
1100100011
0000110001
0000000011
0000000000
0100000100
0001000000
0001000000
0001100000

Sample Output:

7 8

A-2 Queue Using Two Stacks

A queue (FIFO structure) can be implemented by two stacks (LIFO structure) in the following way:

  1. Start from two empty stacks s1​ and s2​.
  2. When element e is enqueued, it is actually pushed onto s1​.
  3. When we are supposed to dequeue, s2​ is checked first. If s2​ is empty, everything in s1​ will be transferred to s2​ by popping from s1​ and immediately pushing onto s2​. Then we just pop from s2​ – the top element of s2​ must be the first one to enter s1​ thus is the first element that was enqueued.

Assume that each operation of push or pop takes 1 unit of time. You job is to tell the time taken for each dequeue.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤103), which are the number of operations. Then N lines follow, each gives an operation in the format

Operation Element

where Operation being I represents enqueue and O represents dequeue. For each I, Element is a positive integer that is no more than 106. No Element is given for O operations.
It is guaranteed that there is at least one O operation.

Output Specification:

For each dequeue operation, print in a line the dequeued element and the unites of time taken to do this dequeue. 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 the queue is empty when dequeue is called, output in a line ERROR instead.

Sample Input:

10
I 20
I 32
O
I 11
O
O
O
I 100
I 66
O

Sample Output:

20 5
32 1
11 3
ERROR
100 5

A-3 Rank of Binary Tree

Here we define the rank of a binary tree as n1​×n2​/n0​ where ni​ is the number of nodes of degree i for i=0,1,2.
For example, given a tree shown by the figure, its rank is 2×3/4=1.5.

fig.jpg

Given the inorder and preorder traversal sequences of a binary tree, you are supposed to calculate its rank.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤20), which is the total number of nodes in the tree. Then given in the following 2 lines are the inorder and preorder traversal sequences of the tree, respectively. All the keys in the tree are distinct positive integers in the range of int.

Output Specification:

For each case, print in a line the way we calculate the rank, and the integer part of the rank. The format is:

n1 * n2 / n0 = rank

Sample Input:

9
2 3 1 5 4 7 8 6 9
1 2 3 6 7 4 5 8 9

Sample Output:

2 * 3 / 4 = 1

A-4 Big Number

How to generate a big number of N digits randomly? One way is to find N kids, give each one a card with one’s index written on one side (hence it is assumed that the kids are indexed from 1 to N), and ask them to write down a 1-digit number randomly on the other side. Then let the kids pin their digits in a line, on the wall, one by one in ascending order of their indices.

However, it’s very difficult to let hundreds of thousands of kids to follow the order. The result is that we have cards pinned randomly all over the wall, some even show the wrong sides. For example, if the 23rd kid has written down 8, we are supposed to find the number 8 on the wall. But instead we might find 23… Your job is to rearrange these cards so that we can obtain the big number as required.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤105). Then N lines follow, each describes a card in the format n1 n2 where the two numbers are the numbers written on the two sides of a card.

Output Specification:

For each test case, print in a line the N-digit number as required. That is, print the digits written by the kids in ascending order of their indices. In case that there are 1-digit numbers written on both sides, it would be hard to tell which one is the index and which one is the number written by the kid. Hence the solution may not be unique. In this case, just output the smallest resulting number.

It is guaranteed that a solution exists.

Sample Input:

12
7 11
8 9
3 1
2 12
4 6
10 0
5 1
2 5
6 8
1 4
7 2
9 3

Sample Output:

359114268072
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值