PTA甲级模拟第六弹:1156-1159


title: 甲级模拟1156-1159
date: 2022-02-02 11:44:50
categories:

  • 算法与数据结构
    tags:
  • 编程练习
  • PTA

1. 知识点总结

今天没有计时(应该超了……)唯一没有AC的测试点居然是1158😅,所以倒数两题小心为上,稳住心态~

本次作业涉及到的知识点有:

  • 简单数学
  • 字符串处理+结构体排序+STL(可选)
  • 并查集
  • STL使用+树
题号难度知识点
1156🐸简单数学(素数判断)
1157🐸字符串处理+结构体排序
1158🐸🐸并查集+STL
1159🐸🐸树(难度还可以,虽然代码长度比较……但是考察基础,没有卡时间)

2. 分题题解

2.1 第一题:PTA甲级1156

考察简单数学:

给定一个N,如果N+6和N同时为素数 或者N-6和N同时为素数则认为是sexy的数字

#include<bits/stdc++.h>
using namespace std;
bool isPrime(int x){
	if(x<=1)return false;
	if(x==2||x==3||x==5||x==7)return true;
	for(int i=2;i*i<=x;i++){
		if(x%i==0)return false;
	}
	return true;
}
int x;
int ans;
bool isSexy(int x){
	if(isPrime(x)&&isPrime(x+6))return true;
	if(isPrime(x)&&isPrime(x-6))return true;
	return false;
}
int main(){
	scanf("%d",&x);
	if(isSexy(x)){
		printf("Yes\n");
		if(isPrime(x-6)){
			printf("%d",x-6);
		}else{
			printf("%d",x+6);
		}
		
	}else{
		printf("No\n");
		ans=x+1;
		while(!isSexy(ans)){
			ans++;
		}
		printf("%d",ans);
	}
	
	return 0;
}

2.2 第二题:PTA甲级1157

字符串处理+结构体排序:简单题

#include<bits/stdc++.h>
using namespace std;
int N;
int M; 
map<string,bool>alumni; 
vector<string>comer;
vector<string>ans;
string temp;
bool cmp(string a,string b){
	if(a.length()!=b.length()){
		return a.length()>b.length();
	}else{
		string tempa=a.substr(6,8);
		string tempb=b.substr(6,8);
		return tempa<tempb;//出生日期小的 
	}
}
int main(){
	scanf("%d",&N);
	for(int i=0;i<N;i++){
		cin>>temp;
		alumni[temp]=true;
	}
	scanf("%d",&M);
	comer.resize(M);
	for(int i=0;i<M;i++){
		cin>>comer[i];
		if(alumni[comer[i]]==true){
			ans.push_back(comer[i]);
		}
	}
	int cnt=ans.size();
	printf("%d\n",cnt);
	if(cnt==0){
		sort(comer.begin(),comer.end(),cmp);
		cout<<comer[0]; 
	}else{
		sort(ans.begin(),ans.end(),cmp);
		cout<<ans[0]; 
	}
	
	return 0;
}

2.3 第三题:PTA甲级1158

比较魔幻的一道题:

思路不是很难,注意细节就好~

思路1:绕开了并查集(因为忘记了)……然后杯具了

当我注释掉61行,第二个测试点不过🙄

当我注释掉60行,第四个测试点不过🙄

就离谱的麻麻给离谱开门……离谱到家了(好叭,菜是原罪)

思路2:

并查集输出gang

思路一

复查的时候发现为啥并查集绕不开了(a-b b-c情况下……a与c还是一窝的😂),下面的代码没有解决这个问题

#include<bits/stdc++.h>
using namespace std;
//
int k,m,n;
int caller,receiver,duration;
vector<int>suspects;
const int maxn=1009;
int hasConnect[maxn][maxn];
bool vis[maxn];
//打印出犯罪团伙 
int main(){
	scanf("%d%d%d",&k,&n,&m);
	memset(hasConnect,-1,sizeof(hasConnect));
	memset(vis,false,sizeof(vis));
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&caller,&receiver,&duration);
		if(hasConnect[caller][receiver]==-1){
			hasConnect[caller][receiver]=duration;
		}else{
			hasConnect[caller][receiver]+=duration;
		}
	} 
	for(int i=1;i<=n;i++){
		int cnt=0;//短电话,打出去的 
		int back=0; //回复的 
		for(int j=1;j<=n;j++){
			if(hasConnect[i][j]==-1)continue;//没有打过
			if(hasConnect[i][j]<=5&&hasConnect[j][i]==-1){
				cnt++;
			} else if(hasConnect[i][j]<=5&&hasConnect[j][i]!=-1){
				cnt++;
				back++;
			}	
		}
		if(cnt>k&&back<=0.2*cnt){
			suspects.push_back(i);
		}
	}
	int len=suspects.size();
	
	
	
	//上面没有问题 
	if(len==0){
		printf("None");
	}else{
		//彼此之间有联系的属于同一个犯罪集团
		sort(suspects.begin(),suspects.end());
		for(int i=0;i<len;i++){
			//输出头领 
			if(!vis[suspects[i]]){
				printf("%d",suspects[i]);
				vis[suspects[i]]=true;
			}else{
				continue;
			}
			//输出跟班 
			for(int j=i+1;j<len;j++){
				//相互打电话 
				//if((hasConnect[suspects[i]][suspects[j]]!=-1&&hasConnect[suspects[j]][suspects[i]]!=-1)&&!vis[suspects[j]]){
				if((hasConnect[suspects[i]][suspects[j]]!=-1||hasConnect[suspects[j]][suspects[i]]!=-1)&&!vis[suspects[j]]){
					printf(" %d",suspects[j]);
					vis[suspects[j]]=true;
				}else{
					continue;
				}	
			}
			printf("\n");
		} 
	}
	return 0;
}

思路二

没啥好说的,并查集好好复习🙄,比较基础

注意的是,首先过滤得到suspects数组,然后对它做并查集的时候,用了map<int,int>存储父节点

为了正序输出,用了map<int,set<int> >存储答案,默认升序

参考博客里给了DFS和并查集两种做法,目前暂时先巩固并查集😁

#include<bits/stdc++.h>
using namespace std;
//并查集解法
int k,m,n;
int caller,receiver,duration;
vector<int>suspects;
const int maxn=1009;
int hasConnect[maxn][maxn];
bool vis[maxn];
//打印出犯罪团伙 
//并查集模板
map<int,int>f;
int Find(int x){
	int a=x;
	while(x!=f[x]){
		x=f[x];
	}
	//减少时间复杂度
	
	int temp;
	while(a!=f[a]){
		temp=a;
		a=f[a];
		f[temp]=x;
	}
	return x;
} 
void Union(int a,int b){
	int fa=Find(a);
	int fb=Find(b);
	if(fa<fb){
		f[fb]=fa;
	}else{
		f[fa]=fb;
	}
}
int main(){
	scanf("%d%d%d",&k,&n,&m);
	memset(hasConnect,-1,sizeof(hasConnect));
	memset(vis,false,sizeof(vis));
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&caller,&receiver,&duration);
		if(hasConnect[caller][receiver]==-1){
			hasConnect[caller][receiver]=duration;
		}else{
			hasConnect[caller][receiver]+=duration;
		}
	} 
	for(int i=1;i<=n;i++){
		int cnt=0;//短电话,打出去的 
		int back=0; //回复的 
		for(int j=1;j<=n;j++){
			if(hasConnect[i][j]==-1)continue;//没有打过
			if(hasConnect[i][j]<=5&&hasConnect[j][i]==-1){
				cnt++;
			} else if(hasConnect[i][j]<=5&&hasConnect[j][i]!=-1){
				cnt++;
				back++;
			}	
		}
		if(cnt>k&&back<=0.2*cnt){
			suspects.push_back(i);
		}
	}
	int len=suspects.size();
	//上面没有问题 
	if(len==0){
		printf("None");
	}else{
		//并查集 
		for(int i=0;i<len;i++){
			f[suspects[i]]=suspects[i];//初始化 
		}
		for(int i=0;i<len;i++){
			for(int j=0;j<len;j++){
				if(hasConnect[suspects[i]][suspects[j]]!=-1&&hasConnect[suspects[j]][suspects[i]]!=-1){
					Union(suspects[i],suspects[j]);
				}
			}
		}
		map<int,set<int> >ans;
		for(int i=0;i<len;i++){
			int id=suspects[i];
			int fid=Find(id);
			ans[fid].insert(id);
		}
		//输出答案
		for(map<int,set<int> >::iterator it=ans.begin();it!=ans.end();it++){
			set<int>temp=it->second;
			bool flag=false;
			for(set<int>::iterator it2=temp.begin();it2!=temp.end();it2++){
				if(!flag){
					flag=true;
				}else{
					printf(" ");
				}
				printf("%d",*it2);
				
			}
			printf("\n");
		} 
	}
	return 0;
}

2.4 第四题:PTA甲级1159

不卡时间……所以,代码虽然长,但是都是基础:

  • 中序遍历+后序遍历建立树
  • 层序遍历的应用(基础)
  • STL中map降低编码难度
  • string中sscanf的使用
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct Node{
	int val;
	int level;
	Node*left=NULL;
	Node*right=NULL;
};
vector<int>post;
vector<int>in; 
//模板了,需要熟悉掌握
Node*build(int postL,int postR,int inL,int inR){
	if(postL>postR){
		return NULL;
	}
	Node *root=new Node;
	root->val=post[postR];
	int k;
	for(k=inL;k<=inR;k++){
		if(in[k]==post[postR]){
			break;
		}
	}
	int left_num=k-inL;
	root->left=build(postL,postL+left_num-1,inL,k-1);
	root->right=build(postL+left_num,postR-1,k+1,inR);
	return root;
}
int isFull(Node*root){
	//除了叶子结点,都有两个孩子
	if(root==NULL){
		return 1;
	}
	if(root->right==NULL&&root->left==NULL){
		return 1;
	} 
	if(root->right==NULL&&root->left!=NULL){
		return 0;
	}
	if(root->right!=NULL&&root->left==NULL){
		return 0;
	}else{
		return isFull(root->left)*isFull(root->right);
	}
	
}
string temp;
map<int,bool>exist;//记录是否出现 
map<int,int>levels;//记录层数 
map<int,int>father;
map<int,int>rchild;
map<int,int>lchild;
void levelTravel(Node*root){
	queue<Node*>q;
	root->level=1;
	q.push(root);
	while(!q.empty()){
		Node *top=q.front();
		levels[top->val]=top->level;//层数 
		q.pop();
		Node*left=top->left;
		Node*right=top->right;
		if(left!=NULL){
			lchild[top->val]=left->val;
			left->level=top->level+1;
			q.push(left);
			father[left->val]=top->val;
		}else{
			lchild[top->val]=-1;
		}
		if(right!=NULL){
			rchild[top->val]=right->val;
			right->level=top->level+1;
			q.push(right);
			father[right->val]=top->val;
		}else{
			rchild[top->val]=-1;
		}
	}
}
int main(){
	scanf("%d",&n);
	post.resize(n);
	in.resize(n);
	for(int i=0;i<n;i++){
		scanf("%d",&post[i]);
		exist[post[i]]=true;
	}
	for(int i=0;i<n;i++){
		scanf("%d",&in[i]);
	}
	Node *root=NULL;
	root=build(0,n-1,0,n-1);
	int isfull=isFull(root);
	levelTravel(root);
	scanf("%d",&m);
	m++;
	while(m--){
		getline(cin,temp);
		int len=temp.length();
		if(temp=="It is a full tree"){
			if(isfull){
				printf("Yes\n");
			}else{
				printf("No\n");
			}
		}else if(temp[len-1]=='t'){//---is the root
			int ask=-1;
			const char *p= temp.c_str();
			sscanf(p,"%d is the root",&ask);
			if(root!=NULL&&root->val==ask){
				printf("Yes\n");
			}else{
				printf("No\n");
			}
		}else if(temp[len-1]=='s'){//-- and -- are siblings
			int a,b;
			const char *p= temp.c_str();
			sscanf(p,"%d and %d are siblings",&a,&b);
			if(exist[a]&&exist[b]){
				if(a==b||father[a]&&father[b]&&father[a]==father[b])
				printf("Yes\n");
				else{
					printf("No\n");
				}
			}else{
				printf("No\n");
			}
		}else if(temp[len-1]=='l'){//-- and -- are on the same level
			int a,b;
			const char *p= temp.c_str();
			sscanf(p,"%d and %d are on the same level",&a,&b);
			if(exist[a]&&exist[b]){
				if(levels[a]==levels[b]){
					printf("Yes\n");
				}else{
					printf("No\n");
				}
			}else{
				printf("No\n");
			}
		}else if(temp.find('p')!=string::npos){//32 is the parent of 11
			int a,b;
			const char *p= temp.c_str();
			sscanf(p,"%d is the parent of %d",&a,&b);
			if(exist[a]&&exist[b]){
				if(father[b]&&father[b]==a){
					printf("Yes\n");
				}else{
					printf("No\n");
				}
			}else{
				printf("No\n");
			}
		
		}else if(temp.find('r')!=string::npos){//28 is the right child of 2
			int a,b;
			const char *p= temp.c_str();
			sscanf(p,"%d is the right child of %d",&a,&b);
			if(exist[a]&&exist[b]){
				if(rchild[b]&&rchild[b]==a){
					printf("Yes\n");
				}else{
					printf("No\n");
				}
			}else{
				printf("No\n");
			}
		}else if(temp.find('l')!=string::npos){//28 is the left child of 2
			int a,b;
			const char *p= temp.c_str();
			sscanf(p,"%d is the left child of %d",&a,&b);
			if(exist[a]&&exist[b]){
				if(lchild[b]&&lchild[b]==a){
					printf("Yes\n");
				}else{
					printf("No\n");
				}
			}else{
				printf("No\n");
			}
		}
	
	}
	return 0;
} 

3. 参考资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值