2019年春PAT甲级总结
- 第一题
题意:Sexy primes的意思是p和p+6两个数都是素数的情况下,这俩数都可以称为sexy prime,给出一个数t,判断这个数是否为sexy prime,若是,则输出Yes和两个数中最小的数,若不是,输出No,找出比t大的最小的sexy prime并输出。
这道题模拟的时候没有读懂题,一直想的是区间范围,pair其实是一对的意思,按素数和区间做的,得了14分。
改正后的代码如下:
思路:考察素数的判定。
step1:先判断t-6和t是不是一对sexy primes,若是,输出。否则,判断t+6和t,若是一对sexy数,输出。
step2:都不满足的情况下,ans=t+1,循环判断ans和(ans-6)或(ans+6)ans++,成立时输出ans。
#include <iostream>
#include <cmath>
using namespace std;//题解:题目中的Sexy primes的意思是p和p+6两个数都是素数的情况下,这俩数都可以称为sexy prime
bool isprime(int x){
if(x <= 1)
return false;
for(int i = 2; i <= sqrt(x); ++ i)
if(x % i == 0)
return false;
return true;
}
int main(){
int x, ans;
scanf("%d", &x);
if(isprime(x)){
if(isprime(x - 6)){
printf("Yes\n%d", x - 6);
return 0;
}
if(isprime(x + 6)){
printf("Yes\n%d", x + 6);
return 0;
}
}
ans = x + 1;
while(!(isprime(ans) && (isprime(ans - 6) || isprime(ans + 6))))
ans ++;
printf("No\n%d",ans);
}
- 第二题
题意:浙大校庆发出了n份邀请函,每个邀请函都有编号,同时来参加校庆的有m人,这些人也有编号,来参加校庆的人中,街道邀请函的有多少人,并输出最大年龄的人的编号。若收到邀请函的人都没来,则输出参加校庆的人中,年龄最大人的编号。
考察map,结构体排序:一次AC了,直接贴代码:
#include<bits/stdc++.h>
using namespace std;
map<string,int>Map;
struct node
{
char gest_id[20];
char cun[20];
}gest[100010];
struct Node
{
char peo_id[20];
char cun[20];
}peo[100010];
bool cmp_gest(node a,node b)
{
return strcmp(a.cun,b.cun)<0;
}
bool cmp_peo(Node a,Node b)
{
return strcmp(a.cun,b.cun)<0;
}
int main()
{
int n,m;
cin>>n;
int num=0;
for(int i=0;i<n;i++)
{
scanf("%s",gest[i].gest_id);
Map[gest[i].gest_id]=1;
strcpy(gest[i].cun,gest[i].gest_id+6);
}
cin>>m;
for(int i=0;i<m;i++)
{
scanf("%s",peo[i].peo_id);
strcpy(peo[i].cun,peo[i].peo_id+6);
if(Map[peo[i].peo_id]==1)
{
num++;
}
}
sort(gest,gest+n,cmp_gest);
sort(peo,peo+m,cmp_peo);
if(num==0)
{
printf("0\n");
printf("%s",peo[0].peo_id);
}
else
{
printf("%d\n",num);
printf("%s",gest[0].gest_id);
}return 0;
}
- 第三题
第三题不知道怎么保存读入的数据,不知道怎么处理,感觉是并查集的应用。
题意:关于电话诈骗的背景。第一行给出通话个数阈值,参加通话的人(从1—n表示),给出m条通话信息,接下去m行是m条信息。每条信息的格式为 发起者,接通者,通话时长
如果一个人打了超过k个短电话给不同的人,但是不超过20%的人打回来,这个人就是诈骗者,诈骗者之间打电话,那么他们属于同一团伙。
要求输出每个团伙中诈骗成员的编号,每个团伙占一行,团伙顺序按团队中最小的诈骗者编号排序,一个团伙中也按诈骗者编号增序输出。
思路:图的应用加并查集
step1:先找出可以的人
step2:应用并查集合并
step3:对团伙排序
参考csdn代码!!!堪称经典!!!
代码如下:(参考此博客,自己写的代码)
//写完之后把这四题的代码全部提交了一遍,这一题只有15分,出错在两结点合并时没有注意要将结点标号小的作为父节点,同时,最后为父节点动态数组push_back时,不应用father[i]作为结点i的父结点下标,而应用find(i)作为下标,改正后代码和源代码如下
#include<bits/stdc++.h>
using namespace std;
vector<int>root[1010];
int G[1010][1010]={0};
int bad[1010]={0};
int father[1010]={0};
int k,n,m;
int find(int f)
{
while(father[f]!=f)
f=father[f];
return f;
}
void merge(int x,int y)
{
int a=find(x);
int b=find(y);
//if(a!=b)
// father[a]=b;
//改为
if(a!=b)
{
if(a<b)father[b]=a;
else father[a]=b;
}
}
int main()
{
for(int p=1;p<1010;p++)
father[p]=p;
cin>>k>>n>>m;
int i,j,time;
for(int t=0;t<m;t++)
{
scanf("%d%d%d",&i,&j,&time);
G[i][j]+=time;
}
for(i=1;i<=n;i++)
{
int num=0,num_hao=0;
for(j=1;j<=n;j++)
{
if(G[i][j]>0&&G[i][j]<=5)
{
num++;//表示short电话的数目
if(G[j][i]>0)
num_hao++;//表示回打电话的数目
}
}
if(1.0*num_hao/num<=0.2&&num>k)
bad[i]=1;
}
for(i=1;i<=n;i++)
{
if(bad[i])
{
for(j=1;j<=n;j++)
{
if(G[i][j]>0&&G[j][i]>0&&bad[j])
{
merge(i,j);
}
}
}
}
int flag=0;
for(i=1;i<=n;i++)
{
if(bad[i]==1)
{
flag=1;
//改正root[father[i]].push_back(i);
//改为
root[find(i)].push_back(i);
}
}
for(i=1;i<n;i++)
{
if(root[i].size()!=0)
for(int q=0;q<root[i].size();q++)
{
if(q!=root[i].size()-1)
printf("%d ",root[i][q]);
else
printf("%d\n",root[i][q]);
}
}
if(flag==0)
printf("None\n");
return 0;
}
- 第四题
题意:给定一个二叉树的后序和中序序列,构造这个二叉树,并判断若干问题是否成立。
思路:step1:由中序和后序构造出这个二叉树(静态二叉树)
step2:因为full二叉树的定义是该结点有孩子就必须是同时有左孩子和右孩子,因此需要用BFS去搜索,来给定是否所有结点满足条件,同时还需要用到标记深度,标记父亲结点来为接下去的判定做铺垫。
step3:用字符串读入的方式去读入问题,接下去根据对应的问题进行输出。
代码如下:(代码是自己打的,参考此博客思路)
代码如下:
#include<bits/stdc++.h>
using namespace std;
int post[50],in[50];
int num=0;
int n;
struct Node
{
int lchild,rchild;
int depth;
int father;
}tree[1010];
int create(int postl,int postr,int inl,int inr)//利用后序和中序建树
{
if(postl>postr)
{
return -1;
}
int root=post[postr];
tree[root].lchild=-1;
tree[root].rchild=-1;
int k;
for(int i=0;i<n;i++)
{
if(in[i]==root)
k=i;
}
int sub=k-inl;
tree[root].lchild=create(postl,postl+sub-1,inl,k-1);
tree[root].rchild=create(postl+sub,postr-1,k+1,inr);
return root;
}
int flag=0;
void BFS(int t)
{
queue<int>qu;
qu.push(t);
tree[t].depth=1;
while(!qu.empty())
{
int cur=qu.front();
qu.pop();
int flagL=0,flagR=0;
if(tree[cur].lchild!=-1)
{
flagL=1;
tree[tree[cur].lchild].depth=tree[cur].depth+1;
tree[tree[cur].lchild].father=cur;
qu.push(tree[cur].lchild);
}
if(tree[cur].rchild!=-1)
{
flagR=1;
tree[tree[cur].rchild].depth=tree[cur].depth+1;
tree[tree[cur].rchild].father=cur;
qu.push(tree[cur].rchild);
}
if((flagR==0&&flagL==1&&flag==0)||(flagL==0&&flagR==1&&flag==0))
flag=1;
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&post[i]);
for(int i=0;i<n;i++)
{
scanf("%d",&in[i]);
}
int root=create(0,n-1,0,n-1);
BFS(root);
string s[10];
int m;
cin>>m;
while(m--)
{
for(int i=0;i<10;i++)
{
cin>>s[i];
int c=getchar();
if(c=='\n')
break;
}
for(int i=0;i<10;i++)
{
if(s[i]=="root")
{
if(stoi(s[0])==root)
printf("Yes\n");
else
printf("No\n");
break;
}
if(s[i]=="siblings")
{
if(tree[stoi(s[0])].father==tree[stoi(s[2])].father)
printf("Yes\n");
else
printf("No\n");
break;
}
if(s[i]=="parent")
{
if(tree[stoi(s[5])].father==stoi(s[0]))
printf("Yes\n");
else
printf("No\n");
break;
}
if(s[i]=="left")
{
if(tree[stoi(s[6])].lchild==stoi(s[0]))
printf("Yes\n");
else
printf("No\n");
break;
}
if(s[i]=="right")
{
if(tree[stoi(s[6])].rchild==stoi(s[0]))
printf("Yes\n");
else
printf("No\n");
break;
}
if(s[i]=="level")
{
if(tree[stoi(s[0])].depth==tree[stoi(s[2])].depth)
printf("Yes\n");
else
printf("No\n");
break;
}
if(s[i]=="full")
{
if(flag==0)
printf("Yes\n");
else
printf("No\n");
break;
}
}
}
}
第二此刷模拟题,只完完整整的AC了一题,还需要增加做题量,同时提高做题速度,读英语的能力!继续刷!
本文总结了PAT甲级考试中的四道编程题,涉及素数判断、地图数据结构操作、电话诈骗团伙识别(并查集应用)以及二叉树构造与属性验证。通过代码解析,分析了解题思路和常见错误,强调了理解题意、数据结构运用和算法优化的重要性。
4019

被折叠的 条评论
为什么被折叠?



