2022冬季(模拟考试)

目录

前言:

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:;
			}
		}
	}
}

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值