PAT甲级_2022冬

总结

第二次模考,74分。
请添加图片描述

第一题:

理解错误点:以为a、b共同出现的数字需要全被删除。
正确思路:相同的数字顺序一一对应消除。
字符串的处理可以单独设置一个与之对应的bool型数组记录每个结点是否需要删除,遍历完后统一删除处理。

第二题:

简单签到题。

第三题:

思路1:邻接表法+DFS - 段错误,想是可能递归层数太深,于是改为BFS。时间复杂度 = O((n + m) * k)
思路2:邻接表法+BFS - 仍然段错误。
思路3:邻接矩阵法+BFS, AC了。
后来检查发现应该是【邻接表数组开小了】。这个问题也是晴神机试模拟第三天中没拿到满分的原因,要重视。
思路4:并查集(待验证),时间复杂度 = O(mk)

第四题:

这题没时间了,简单写写只骗了4分。
先序+后序判断是否能构成树:
由 根左右 & 左右根 的特性,知道先序中第二个元素一定是子树的根,然后找后序中与之对应的位置,并尝试构造此子树。可设置flag记录是否正确,如果确定不能构造则进入下层循环后直接返回。

//判断先序、后序遍历是否能构成树
void judge(int pl, int pr, int pol, int por){
	if(pl > pr || flag) return;
	else if(pl == pr && pre[pl] == post[por]) return; 
	else if(pre[pl] != post[por]){
		flag = true;
		return;
	}
	int i = pol;
	while(i <= por && pre[pl + 1] != post[i]) i ++;
	if(i > por){
		flag = true;
		return;
	}
	judge(pl + 1, pl + 1 + i - pol, pol, i);
	judge(pl + 2 + i - pol, pr, i + 1, por - 1);
}

A-1 Reduction of Proper Fractions

A 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
#include<bits/stdc++.h>
using namespace std;
string ia, ib, oa, ob;
int a, b, i, j; 
bool st[10]; 
int main(){
	cin>>a>>b; 
	printf("%d/%d", a, b);
	ia = to_string(a), ib = to_string(b);
	long double l = (long double)a / (long double)b, r;
	memset(st, true, sizeof st);
	for(i = 0; i < ia.size(); i++){
		bool f = false;
		for(j = 0; j < ib.size(); j++){
			if(st[j] && ia[i] == ib[j]){
				st[j] = false;
				f = true;
				break;
			}
		}
		if(!f) oa += ia[i];
	}
	memset(st, true, sizeof st);
	for(i = 0; i < ib.size(); i++){
		bool f = false;
		for(j = 0; j < ia.size(); j++){
			if(st[j] && ib[i] == ia[j]){
				st[j] = false;
				f = true;
				break;
			}
		}
		if(!f) ob += ib[i];
	}
	if(oa.size() == 0) oa = "0";
	if(ob.size() == 0) ob = "0";
	oa = to_string(stoi(oa)), ob = to_string(stoi(ob));
	if(ob == "0") r = 99999;
	else if(oa == "0") r = 0;
	else r = (long double)stoi(oa) / (long double)stoi(ob);
	printf(l == r ? "= " : "!= ");
	cout<<oa<<'/'<<ob; 
	return 0;
}
	简化了一遍(待检验)。思路是两个指针加一个tag记录指针指向元素是否存在。
#include<bits/stdc++.h>
using namespace std;
string ia, ib, oa, ob;
int main(){
	cin>>ia>>ib; cout<<ia<<'/'<<ib;
	vector<bool> sta(ia.size(), 1), stb(ib.size(), 1);
	for(int i = 0; i < ia.size(); i ++) 
		for(int j = 0; j < ib.size(); j ++)
			if(stb[j] && ia[i] == ib[j])
				sta[i] = stb[j] = false;
	for(int i = 0; i < ia.size(); i++)
		if(sta[i]) oa += ia[i];
	for(int i = 0; i < ib.size(); i++)
		if(stb[i]) ob += ib[i];
	if(!oa.size()) oa = "0";
	if(!ob.size()) ob = "0";
	if(oa == "0" || ob == "0" || (double)stoi(ia) / stoi(ib) != (double)stoi(oa) / stoi(ob)) cout<<" != ";
	else cout<<" = ";
	cout<<oa<<'/'<<ob;
	return 0;
} 

A-2 Luggage Pickup

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 n, tmp, cnt, t;
int main(){
	cin>>n;
	vector<int> pas(n + 1);
	for(int i = 1; i <= n; i ++) scanf("%d", &pas[i]);
	for(int i = 1; i <= n; i ++){
		while(pas.front() != i){
			int tmp = pas.front();
			pas.pop();
			pas.push(tmp);
			t++;
			cnt += pas.size();
		}
		t++;
		cnt += pas.size();
		pas.pop();
	}
	printf("%d %.1lf", t, (double)cnt / n);
	return 0;
}

A-3 Articulation Point

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
#include<bits/stdc++.h>
using namespace std;
const int N = 10001;
int n, m, k, tar, cnt, v1, v2, sta;
int g[1001][1001];
bool st[N];
int main(){
	cin>>n>>m>>k;
	while(m--){
		cin>>v1>>v2;
		g[v1][v2] = g[v2][v1] = 1;
	}
	while(k--){
		memset(st, false, sizeof st);
		cnt = 1;
		cin>>tar; st[tar] = true;
		for(int i = 0; i < n; i++){
			if(g[tar][i] != 0){
				sta = i;
				break;
			}
		}
		queue<int> que; que.push(sta); st[sta] = true;
		while(que.size()){
			cnt++; int t = que.front(); que.pop();
			for(int i = 0; i < n; i++){
				if(g[i][t] == 1 && !st[i]){
					st[i] = true;
					que.push(i);
				}
			}
		}
		printf(cnt == n ? "0" : "1");
	}
	return 0;
}

邻接表法+DFS未通过代码:
修改后未检测,修改位置:N = 10001改为30001,因为边在 1 0 4 10^4 104。N之前应该是开小了

#include<bits/stdc++.h>
using namespace std;
const int N = 30001;
int n, m, k, tar, cnt, v1, v2;
int e[N], ne[N], h[N], idx = 0;
bool st[N];
void add(int a, int b){
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void DFS(int s){
	st[s] = true, cnt++;
	for(int i = h[s]; i != -1; i = ne[i]){
		int t = e[i];
		if(!st[t]) DFS(t);
	}
}
int main(){
	cin>>n>>m>>k;
	memset(h, -1, sizeof h);
	while(m--){
		cin>>v1>>v2;
		add(v1, v2), add(v2, v1);
	}
	while(k--){
		memset(st, false, sizeof st);
		cin>>tar; 
		st[tar] = true, cnt = 1;
		int sta = e[h[tar]];//找到第一个结点
		DFS(sta);
		printf(cnt == n ? "0" : "1");
	}
	return 0;
}

邻接表法+BFS

#include<bits/stdc++.h>
using namespace std;
const int N = 30001;
int n, m, k, tar, cnt, v1, v2;
int e[N], ne[N], h[N], idx = 0;
bool st[N];
void add(int a, int b){
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int main(){
	cin>>n>>m>>k;
	memset(h, -1, sizeof h);
	while(m--){
		cin>>v1>>v2;
		add(v1, v2);
		add(v2, v1);
	}
	while(k--){
		memset(st, false, sizeof st);
		cin>>tar; 
		st[tar] = true, cnt = 1;
		int sta = e[h[tar]];
		queue<int> que; que.push(sta); st[sta] = true;
		while(que.size()){
			cnt++; int t = que.front(); que.pop();
			for(int i = h[t]; i != -1; i = ne[i]){
				int j = e[i];
				if(!st[j]){
					que.push(j);
					st[j] = true;
				}
			}
		}
		printf(cnt == n ? "0" : "1");
	}
	return 0;
}

新思路:用并查集,记录 1 0 4 10^4 104边信息,每次合并不包含tar结点的边,然后遍历计算连通分量。(待验证)

#include<bits/stdc++.h>
using namespace std;
const int N = 10001;
int p[N], n, m, k, tar, cnt;
int find(int x){
	if(x != p[x]) p[x] = find(p[x]);
	return p[x];
}
int main(){
	cin>>n>>m>>k;
	vector<pair<int, int>> rec(m);
	for(int i = 0; i < m; i ++) cin>>rec[i].first>>rec[i].second;
	while(k--){
		int tar; cin>>tar;
		for(int i = 0; i < n; i ++) p[i] = i;
		for(int i = 0; i < m; i ++){
			if(rec[i].first == tar || rec[i].second == tar) continue;
			int a = find(rec[i].first), b = find(rec[i].second);
			if(a != b) p[a] = p[b];
		}
		cnt = 0;
		for(int i = 0; i < n; i ++) if(p[i] == i) cnt++;
		printf(cnt == 2 ? "0" : "1");		
	}
	return 0;
} 

A-4 Check Inorder Traversals

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!
#include<bits/stdc++.h>
using namespace std;
const int N = 35;
int pre[N], post[N], in[N], m, n;
vector<int> post2;
bool flag = false, flag2 = false;
struct node{
	int key;
	struct node * l,* r;
};
void judge(int pl, int pr, int pol, int por){
	if(pl > pr || flag) return;
	else if(pl == pr && pre[pl] == post[por]) return; 
	else if(pre[pl] != post[por]){
		flag = true;
		return;
	}
	int i = pol;
	while(i <= por && pre[pl + 1] != post[i]) i ++;
	if(i > por){
		flag = true;
		return;
	}
	judge(pl + 1, pl + 1 + i - pol, pol, i);
	judge(pl + 2 + i - pol, pr, i + 1, por - 1);
}
node * maketree(int pl, int pr, int il, int ir){
	if(pl > pr || flag2) return NULL;
	if(pr - pl != ir - il){
		flag2 = true;
		return NULL;
	}
	int i = il;
	while(i <= ir && pre[pl] != in[i]) i++;
	if(i > ir){
		flag2 = true;
		return NULL;
	}
	node * no = (node*)malloc(sizeof(node));
	no->key = pre[pl];
	no->l = maketree(pl + 1,pl + i - il, il, i - 1);
	no->r = maketree(pl + i - il + 1, pr, i + 1, ir);
	return no;
}
void postorder(node * t){
	if(t == NULL) return;
	if(t->l) postorder(t->l);
	if(t->r) postorder(t->r);
	post2.push_back(t->key);
}
int main(){
	cin>>n;
	for(int i = 0; i < n; i ++) cin>>pre[i];
	for(int i = 0; i < n; i ++) cin>>post[i];
	cin>>m;
	judge(0, n - 1, 0, n - 1);
	if(flag){
		puts("Are you kidding me?");
		while(m --){
			flag2 = false;
			for(int i = 0; i < n; i ++) cin>>in[i];
			node* t = maketree(0, n - 1, 0, n - 1);
			if(flag2) cout<<"You must be kidding me!";
			else{
				post2.clear();
				postorder(t);
				for(int i = 0; i < n - 1; i++) cout<<post2[i]<<' ';
				cout<<post[n - 1];
			}
			if(m != 0) puts("");			
		}
	}else{
		while(m --){
			flag2 = false;
			for(int i = 0; i < n; i ++) cin>>in[i];
			node * t = maketree(0, n - 1, 0, n - 1);
			if(flag2){
				cout<<"No";
				if(m != 0) puts("");
				continue;
			}
			post2.clear();
			postorder(t);
			for(int i = 0; i < n; i++)
				if(post[i] != post2[i]) flag2 = true;
			printf(flag2 ? "No" : "Yes");
			if(m != 0) puts("");
		}
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值