2022冬季(模拟考试)

本文对2022冬季PAT模拟考试的题目进行解析。包括A-1分数化简、A-2行李领取、A-3割点判断、A-4中序遍历检查等题目,分析了各题的题意、思路、坑点,并给出代码。整体卷子难度不大,但AK不易,作者此次考试得85分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言:

A-1 Reduction of Proper Fractions(分数 20)

题目:

思路:

代码:

A-2 Luggage Pickup(分数 25)

题目:

思路:

代码: 

A-3 Articulation Points(分数 25)

题目:

思路:

代码:

A-4 Check Inorder Traversals(分数 30)

题目:

思路:

代码: 


前言:

通过下面的图可以看到,这套卷子主要是1和4比较难,其中1其实并不难,只是英文题面相比于中文题面少了一句话,所以才造成很多人题目读错,通过率较低,对于2和3来说,其实都属于常规题。第4题就比较麻烦一些,但是也不是很难。整套卷子的难度并不是很大,但是想要AK也不容易。最后这套卷子得了85分(第一题9分(读错题了)+最后一题扣了4分(静态建树,没开辟下标,直接用值作为下标了))

A-1 Reduction of Proper Fractions(分数 20)

题目:

Proper Fraction(真分数)is a fraction where the numerator(分子)is less than the denominator(分母). To reduce a fraction, we are supposed to cross out any common factors between the numerator and the denominator.

Here is another way to do the reduction: simply cross out any common digits. In most of the cases, this way cannot give the correct result. However, sometimes it happends to work! For example: 26/65 = 2/5 where 6 is crossed out.

Now given a proper fraction, you are supposed to tell if this simple reduction works or not.

Input Specification:

Each input file contains one test case, with the numerator a and the denominator b of the proper fraction given in a line, separated by a space. It is guaranteed that 0<a<b≤105.

Output Specification:

For each test case, print in a line both fractions before and after the simple reduction. If they are equal, put a = between them; else put != instead. The format is either a/b = c/d or a/b != c/d.

Sample Input 1:

39 195

Sample Output 1:

39/195 = 3/15

Sample Input 2:

1234 2345

Sample Output 2:

1234/2345 != 1/5

Sample Input 3:

1234 5678

Sample Output 3:

1234/5678 = 1234/5678

思路:

这道题的题意其实少了一句话——“当我们删去相同元素的时候,不应该删除所有相同元素,要保证数量也一一对应,且要从左侧删除”。

“simply cross out any common digits”,简单地划去所有公共数字:那么请问①举个例子,a是121,b是12,那么这里的公共数字是1对吧,那是应该删除a中的所有1呢,还是只删除第一个1,这个问题题目根本没说,很无语就;②如何删去这个公共数字,a有两个1,要删除哪个呢?这个题目也没说,但后来的事实验证题目是从左侧删除。

总之,这道题出的就是一陀,导致了很多人第一题被卡,我花了近1h去debug找错,结果最后室友告诉我是题目的问题。。。。。。

在我们理清题意后,其实这道题很简单,可以用两层循环直接暴力;当然也可以先求出a和b中数字的数量,然后取个min,再对a和b从左向右删除即可。

坑点:

需要注意的是当删去公共数字后,由于我们使用字符串存储,若得到的结果为空,需要用0代替,且最后的一定是!=,因为左侧一定不为0.

代码:

由于当时没过,事后补充的,所以如果大家事后做的时候发现可以AC,请在评论区留言。谢谢

#include<bits/stdc++.h>
using namespace std;
string a, b, c, d;
int va[10], vb[10];
vector<int> r(10);

string change(string t, vector<int> p) {
	string k = "";
	for (auto i : t) {
		if (p[i - '0']) p[i - '0']--;
		else k += i;
	}
	if (!k.size()) k += '0';
	return k;
}

int main() {
	cin >> a >> b;
	for (auto i : a) va[i - '0']++;
	for (auto i : b) vb[i-'0']++;
	for (int i = 0;i < 10;i++) r[i] = min(va[i], vb[i]);
	c = change(a, r), d = change(b, r);
	cout << a << "/" << b;
	if (stoi(a) * stoi(d) == stoi(b) * stoi(c) && stoi(d) != 0)cout << " = ";
	else cout << " != ";
	cout << c << "/" << d;
}

再附上一个最初的思路的9分代码:(你会发现有很多运行时错误,这是因为有一些点删除后是空,那么stoi转空字符串会自然会有问题) 

#include<bits/stdc++.h>
using namespace std;
string a, b, a1, b1;

int main() {
	cin >> a >> b;
	set<int> s;
	for (auto i : a)
		s.insert(i);
	for (auto i : b) {
		if (s.find(i) == s.end())
			b1 += i;
		else s.erase(i);
	}
	for (auto i : a) {
		if (s.find(i) != s.end())
			a1 += i;
	}
	int x1 = stoi(a);
	int x2 = stoi(b);
	int y1 = stoi(a1);
	int y2 = stoi(b1);
	cout << a << "/" << b;
	if (x1 * y2 == x2 * y1)
		cout << " = ";
	else
		cout << " != ";
	cout << y1 << "/" << y2;
}

A-2 Luggage Pickup(分数 25)

题目:

lug.jpg

When a flight arrives, the passengers will go to the Arrivals area to pick up their baggage from a luggage conveyor belt (行李传送带).

Now assume that we have a special airport that has only one pickup window for each conveyor belt. The passengers are asked to line up to pick up their luggage one by one at the window. But if one arrives at the window yet finds out that one is not the owner of that luggage, one will have to move to the end of the queue and wait for the next turn. At the mean time, the luggage at the window will wait until its owner picks it up. Suppose that each turn takes 1 minute, your job is to calculate the total time taken to clear the conveyor belt, and the average waiting time for the passengers.

For example, assume that luggage i belongs to passenger i. If the luggage come in order 1, 2, 3, and the passengers come in order 2, 1, 3. Luggage 1 will wait for 2 minutes to be picked up by passenger 1. Then the luggage queue contains 2 and 3, and the passenger queue contains 3 and 2. So luggage 2 will wait for 2 minutes to be picked up by passenger 2. And finally 3 is done at the 5th minute. The average waiting time for the passengers is (2+4+5)/3≈3.7.

Input Specification:

Each input file contains one test case. The first line gives a positive integer N (≤103). Then N numbers are given in the next line, which is a permutation of the integers in [1,N], representing the passenger queue. Here we are assuming that the luggage queue is in order of 1, 2, ..., N, and the i-th luggage belongs to passenger i.

All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in a line the total time taken to clear the conveyor belt, and the average waiting time for the passengers (output 1 decimal place). 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:

5
3 5 1 2 4

Sample Output:

9 6.0

思路:

这个题就比较简单了,就是一个排队问题,模拟即可

代码: 

#include<bits/stdc++.h>
using namespace std;
int tag = 1;
int N;
deque<int> p;

int main() {
	cin >> N;
	for (int i = 0;i < N;i++) {
		int t;cin >> t;
		p.push_back(t);
	}
	int sum = 0, sum2 = 0;
	while (p.size() != 1) {
		int i;
		for (i = 0;p[i] != tag;i++);
		sum += (i + 1);
		sum2 += sum;
		while (i--) {
			int f = p.front();
			p.pop_front();
			p.push_back(f);
		}
		p.pop_front();
		tag++;
	}
	cout << sum + 1 << " " << fixed << setprecision(1) << double(sum2 + sum + 1) / N;
}

A-3 Articulation Points(分数 25)

题目:

ap.jpg

In graph theory, given a connected graph G, the vertices whose removal would disconnect G are known as articulation points. For example, vertices 1, 3, 5, and 7 are the articulation points in the graph shown by the above figure (also given by the sample input).

It is a bit complicated to find the articulation points. Here you are only asked to check if a given vertex is an articulation point or not.

Input Specification:

Each input file contains one test case. For each case, the first line contains 3 positive integers: N (≤103), M (≤104), and K (≤100), which are the number of vertices, the number of edges, and the number of queries, respectively. Then M lines follow, each gives an undirected edge in the format:

v1 v2

where v1 and v2 are the two ends of an edge. Here we assume that all the vertices are numbered from 0 to N−1. It is guaranteed that v1 is never the same as v2, and the graph is connected.

Finally a line of queries are given, which contains K vertices to be checked. The numbers in a line are separated by spaces.

Output Specification:

Output a string of 0's and 1's in a line. That is, for each query, print 1 if the given vertex is an articulation point, or 0 if not. There must be no space between the answers.

Sample Input:

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

Sample Output:

10010101

思路:

这个其实就是从一个肯定是连接图的图中扣出一个结点,若扣除后独立子图个数不为1,则证明该点是割点

代码:

#include<bits/stdc++.h>
using namespace std;
int N, M, K;
vector<int> v[1010];
int vis[1010];

void dfs(int cur,int goal) {
	if (vis[cur]) return;
	vis[cur] = 1;
	for (auto i : v[cur])
		if (i != goal)
			dfs(i, goal);
}

int main() {
	cin >> N >> M >> K;
	for (int i = 0;i < M;i++) {
		int a, b;cin >> a >> b;
		v[a].push_back(b);
		v[b].push_back(a);
	}
	for (int i = 0;i < K;i++) {
		int q;cin >> q;
		int cnt = 0;
		for (int i = 0;i < 1010;i++) vis[i] = 0;
		for (int j = 0;j < N; j++) {
			if (!vis[j] && j != q) {
				dfs(j, q);
				cnt++;
			}
		}
		if (cnt >= 2) cout << "1";
		else cout << "0";
	}
}

A-4 Check Inorder Traversals(分数 30)

题目:

Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences, or preorder and inorder traversal sequences. However, if only the postorder and preorder traversal sequences are given, the corresponding tree may no longer be unique.

Now given a pair of postorder and preorder traversal sequences, you are supposed to check a set of inorder traversal sequences, and answer whether or not they are indeed inorder traversal sequences of the tree.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤ 30), the total number of nodes in the binary tree. The second line gives the preorder sequence and the third line gives the postorder sequence.

Then another positive integer K (≤ 10) is given, followed by K lines of inorder traversal sequences.

Each sequence consists of N positive integers. All the numbers in a line are separated by a space.

Output Specification:

For each inorder traversal sequence, print in a line Yes if it is an inorder traversal sequence of the tree, or No if not.

On the other hand, there is another possible case that the given pre- and postorder traversal sequences can NOT form any tree at all. In that case, first print in a line Are you kidding me?. Then for each inorder traversal sequence of the input, try to construct a tree with the given preorder traversal sequence, and output in a line the correct postorder traversal sequence. If it is still impossible, output You must be kidding me! instead.

Sample Input 1:

4
1 2 3 4
2 4 3 1
4
2 1 3 4
1 2 3 4
2 1 4 3
2 1 5 6

Sample Output 1:

Yes
No
Yes
No

Sample Input 2:

7
1 2 3 4 6 7 5
6 7 5 4 3 2 1
3
2 1 6 4 7 3 5
2 1 6 7 4 3 5
2 3 1 7 4 5 6

Sample Output 2:

Are you kidding me?
2 6 7 4 5 3 1
2 7 6 4 5 3 1
You must be kidding me!

思路:

我的思路比较凌乱,转载一下大佬的思路:

相关链接:2022冬季AK

首先是判断一个前序遍历和后序遍历是否可能构成一颗二叉树。如下例

前序遍历1 2 3 4 5 6

后序遍历3 4 2 6 5 1

前序遍历就是根左右,后序遍历是左右根。因此对于前序遍历而言,其第一个值(下标为0)1便是此时结点的值,而其第二个值(下标为1)2便是左孩子结点的值,若其没有左孩子则为右孩子结点的值。

怎么判断到底有没有左孩子呢?此时就需要后序遍历,其是左右根,对于左孩子结点的值应该出现在后序遍历的左边,对于样例而言其出现在了后序遍历下标为2的位置,因此可以判断后序遍历中的3 4 2是左子树的后序遍历,则剩余部分6 5便是右子树的后序遍历。由于前序遍历和后序遍历的长度一定相同,因此左子树的前序遍历为2 3 4,右子树的后序遍历为5 6。按照此方式便可以递归划分左右子树,以此建树。

那么问题来了,题目是问我(读者)是否可能构成一颗二叉树,按照你(博主)的逻辑好像其一定可以建成啊。那么好,我们此时以样例二来进行以上过程,来判断其为什么不能建成树。如下例

前序遍历1 2 3 4 6 7 5

后序遍历6 7 5 4 3 2 1

首先前序遍历第一个值1为根节点的值,第二个值2为左孩子结点的值,然后在后序遍历中寻找2的位置,发现其在最后一个(1是根节点的值不参与判断),但是按照左右根的顺序,最后一个不应该是右孩子结点的值吗?此时发生了这样一种情况,这个结点没有左孩子或右孩子,那么此时它是左孩子或右孩子都可以(这不是能否建成树的原因),因此我们默认其为左孩子。那么得到如下划分,其中右子树为空故不列举。

前序遍历2 3 4 6 7 5

后序遍历6 7 5 4 3 2

再次划分

3 4 6 7 5

6 7 5 4 3

再次划分

4 6 7 5

6 7 5 4

此时前序遍历中的第二个值6出现在后序遍历的最左边,因此6即为左结点的值,且其没有左右子树,即这个6是一个叶子结点。那么剩下的就是右子树的内容,如下

前序遍历7 5

后序遍历7 5

此时就来到了一种很奇怪的情况,前序遍历的第一个和后序遍历的最后一个不相同,这就是无法构成二叉树的主要原因!!!。还有一个原因在坑点详解中描述。

哈哈哈此时我只是知道了给定的前序遍历和后序遍历能否构成二叉树,我还不知道怎么判断对于查询的中序遍历是否可以由构成的二叉树中序遍历得到。

此时我的逻辑是:如果一个前序遍历和后序遍历构成的可能的二叉树,可以(假设)得到查询的中序遍历,那么我用前序遍历和查询的中序遍历构成的唯一的二叉树就一定可以得到后序遍历;反之如果得不到那么这个中序遍历是不可行的。

坑点详解:

1. 无法建成树的第二个原因,仔细观察样例其实可以发现,对于样例1的第4个查询,其中出现了一个不可能的值6,那么如果你按照这个6去建树,在find的过程中是不可能找到这个6的,因此第二个原因是,在find的过程中无法找到值。正常来讲是绝对可以找到的。

穷举递归思路:

前序是根左右,后序是左右根,因此也可以通过递归的方法在左右之间找分割点,遍历一遍看是否能构成树。 

代码: 

改正后的代码(下标还未改正,等明天再来改,可能问题不出在下标,不过有个段错误,也有可能),如果AC了麻烦大家在评论区留言

写的有些凌乱。

#include<bits/stdc++.h>
using namespace std;
int N, K;
int ppp = 0, lll = 0;
int pre[31], in[31], post[31], p[31];

struct node {
	int l = -1, r = -1;
}v[100];

int build(int h1, int t1, int h2, int t2) {
	if (h1 > t1 || h2 > t2 || lll) return -1;
	int root = pre[h1];
	int i;
	for (i = h2;in[i] != root;i++);
	if (i == t2 + 1) {
		lll = 1;
		return -1;
	}
	v[root].l = build(h1 + 1, i + h1 - h2, h2, i - 1);
	v[root].r = build(t1 - t2 + i + 1, t1, i + 1, t2);
	return root;
}

void hou(int cur) {
	if (cur == -1) return;
	hou(v[cur].l);
	hou(v[cur].r);
	p[ppp++] = cur;
}

int main()
{
	cin >> N;
	for (int i = 0;i < N;i++) cin >> pre[i];
	for (int i = 0;i < N;i++) cin >> post[i];
	bool tag = 0;
	if (pre[0] != post[N - 1]) tag = 1;
	int k = 0;
	for (int i = 1, j = N - 2;i < N && j >= 0;)
	{
		if (pre[i] == post[j])
			i++, j--;
		else {
			if (pre[i] == post[k]) k++, i++;
			else {
				tag = 1;
				break;
			}
			if (pre[i] != post[j]) {
				tag = 1;
				break;
			}
		}
	}
	cin >> K;
	if (tag == 0)
	{
		while (K--)
		{
			ppp = 0, lll = 0;
			for (int i = 0;i < N;i++)
				cin >> in[i];
			int root = build(0, N - 1, 0, N - 1);
			if (lll)
			{
				cout << "No" << endl;
				continue;
			}
			hou(root);
			int k = 0;
			while (p[k] == post[k] && k < N) k++;
			if (k == N)
				cout << "Yes" << endl;
			else
				cout << "No" << endl;
		}
	}
	else {
		cout << "Are you kidding me?" << endl;
		while (K--)
		{
			ppp = 0, lll = 0;
			for (int i = 0;i < N;i++)
				cin >> in[i];
			int root = build(0, N - 1, 0, N - 1);
			if (lll)
			{
				cout << "You must be kidding me!" << endl;
				continue;
			}
			hou(root);
			for (int i = 0;i < N;i++) {
				if (i)
					cout << " ";
				cout << p[i];
			}
			cout << endl;
		}
	}
}

也可以参考绝对正确的大佬的代码:

#include<iostream>
#include<cstdlib>
#include<vector>
using namespace std;
struct node{
	int data;
	node* l;
	node* r;
};
int find(int a,int post[],int length){
	for(int i=0;i<length;i++) if(post[i]==a) return i;
	return length;
}
int flag=0;
void build(int pre[],int post[],int length){
	if(length<=0) return;
	if(pre[0]!=post[length-1]){
		flag=1;
		return ;
	}
	if(length<=1) return;
	int site=find(pre[1],post,length);
	if(site==length){
		flag=1;
		return ;
	}
	build(pre+1,post,site+1);
	build(pre+1+site+1,post+site+1,length-1-site-1);
}
int flag1=0;
node* qzbuild(int pre[],int in[],int length){
	if(length<=0) return NULL;
	node* p=(node*)malloc(sizeof(node));
	p->data=pre[0];
	p->l=NULL;
	p->r=NULL;
	int site=find(pre[0],in,length);
	if(site==length){
		flag1=1;
		return p;
	} 
	p->l=qzbuild(pre+1,in,site);
	p->r=qzbuild(pre+site+1,in+site+1,length-site-1);
	return p;
}
vector <int> ans;
void postorder(node* root){
	if(root!=NULL){
		postorder(root->l);
		postorder(root->r);
		ans.push_back(root->data);
	}
}
int main(){
	int n;
	cin>>n;
	int pre[35];
	int post[35];
	for(int i=0;i<n;i++) cin>>pre[i];
	for(int i=0;i<n;i++) cin>>post[i];
	build(pre,post,n);
	int k;
	cin>>k;
	if(flag){
		cout<<"Are you kidding me?"<<endl;
		for(int i=0;i<k;i++){
			int in[n];
			flag1=0;
			for(int j=0;j<n;j++) cin>>in[j];
			node* root=qzbuild(pre,in,n);
			if(flag1){
				cout<<"You must be kidding me!"<<endl;
			}
			else{
				ans.clear();
				postorder(root);
				for(int i=0;i<n;i++){
					if(i) cout<<" ";
					cout<<ans[i];
				}
				cout<<endl;
			}
		}
	}
	else{
		for(int i=0;i<k;i++){
			int in[n];
			flag1=0;
			for(int j=0;j<n;j++) cin>>in[j];
			node* root=qzbuild(pre,in,n);
			if(flag1){
				cout<<"No"<<endl;
			}
			else{
				ans.clear();
				postorder(root);
				for(int i=0;i<n;i++){
					if(ans[i]!=post[i]){
						cout<<"No"<<endl;
						goto end;
					}
				}
				cout<<"Yes"<<endl; 
				end:;
			}
		}
	}
}

内容概要:本文详细探讨了制造业工厂中两条交叉轨道(红色和紫色)上的自动导引车(AGV)调度问题。系统包含2辆红色轨道AGV和1辆紫色轨道AGV,它们需完成100个运输任务。文章首先介绍了AGV系统的背景和目标,即最小化所有任务的完成时间,同时考虑轨道方向性、冲突避免、安全间隔等约束条件。随后,文章展示了Python代码实现,涵盖了轨道网络建模、AGV初始化、任务调度核心逻辑、电池管理和模拟运行等多个方面。为了优化调度效果,文中还提出了冲突避免机制增强、精确轨道建模、充电策略优化以及综合调度算法等改进措施。最后,文章通过可视化与结果分析,进一步验证了调度系统的有效性和可行性。 适合人群:具备一定编程基础和对自动化物流系统感兴趣的工程师、研究人员及学生。 使用场景及目标:①适用于制造业工厂中多AGV调度系统的开发与优化;②帮助理解和实现复杂的AGV调度算法,提高任务完成效率和系统可靠性;③通过代码实例学习如何构建和优化AGV调度模型,掌握冲突避免、路径规划和电池管理等关键技术。 其他说明:此资源不仅提供了详细的代码实现和理论分析,还包括了可视化工具和性能评估方法,使读者能够在实践中更好地理解和应用AGV调度技术。此外,文章还强调了任务特征分析的重要性,并提出了基于任务特征的动态调度策略,以应对高峰时段和卸载站拥堵等情况。
内容概要:本文介绍了一个使用MATLAB编写的基于FDTD(时域有限差分)方法的电磁波在自由空间中传播的仿真系统。该系统采用了ABC(吸收边界条件)和正弦脉冲激励源,并附有详细的代码注释。文中首先介绍了关键参数的选择依据及其重要性,如空间步长(dx)和时间步长(dt),并解释了它们对算法稳定性和精度的影响。接着阐述了电场和磁场的初始化以及Yee网格的布局方式,强调了电场和磁场分量在网格中的交错排列。然后详细讲解了吸收边界的实现方法,指出其简单而有效的特性,并提醒了调整衰减系数时需要注意的问题。最后,描述了正弦脉冲激励源的设计思路,包括脉冲中心时间和宽度的选择,以及如何将高斯包络与正弦振荡相结合以确保频带集中。此外,还展示了时间步进循环的具体步骤,说明了磁场和电场分量的更新顺序及其背后的物理意义。 适合人群:对电磁波传播模拟感兴趣的科研人员、高校学生及工程技术人员,尤其是那些希望深入了解FDTD方法及其具体实现的人群。 使用场景及目标:适用于教学演示、学术研究和技术开发等领域,旨在帮助使用者掌握FDTD方法的基本原理和实际应用,为后续深入研究打下坚实基础。 阅读建议:由于本文涉及较多的专业术语和技术细节,建议读者提前熟悉相关背景知识,如电磁理论、MATLAB编程等。同时,可以通过动手实践代码来加深理解和记忆。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值