2019年春PAT甲级

本文总结了PAT甲级考试中的四道编程题,涉及素数判断、地图数据结构操作、电话诈骗团伙识别(并查集应用)以及二叉树构造与属性验证。通过代码解析,分析了解题思路和常见错误,强调了理解题意、数据结构运用和算法优化的重要性。
摘要由CSDN通过智能技术生成

2019年春PAT甲级总结

  1. 第一题
    题意: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);
}
  1. 第二题
    题意:浙大校庆发出了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. 第三题
    第三题不知道怎么保存读入的数据,不知道怎么处理,感觉是并查集的应用。
    题意:关于电话诈骗的背景。第一行给出通话个数阈值,参加通话的人(从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;
}
  1. 第四题
    题意:给定一个二叉树的后序和中序序列,构造这个二叉树,并判断若干问题是否成立。
    思路: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了一题,还需要增加做题量,同时提高做题速度,读英语的能力!继续刷!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值