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