PAT(甲级)2021年春季考试

PAT(甲级)2021年春季考试

7-1 Arithmetic Progression of Primes (20 分) 暴力搜索

【解题思路】

输入n的范围最大只有10,我们可以暴力搜索。

首先打表生成2到MAXP的所有素数。

最大的公差可能值为(MAXP-2)/(n-1),我们从大往小搜索,判断是否符合条件,如果符合则记录答案,结束循环。

特判,如果n=1,或者不存在符合条件的等差数列,直接输出小于MAXP的最大的素数。

注意,这里我们将素数存在数组当中。如果使用vector,样例4会段错误,不知道原因。

【满分代码】

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=100005;
bool p[maxn];
int v[maxn];
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n,m,size=0;
	cin>>n>>m;
	for(int i=2;i<=m;i++)
	{
		if(!p[i])
		{
			v[size++]=i;
			//vec.emplace_back(i);
			for(int j=2*i;j<=m;j+=i)
				p[j]=1;
		}
	}//素数打表 
	//cout<<size<<endl;
	int dif=(m-2)/(n-1),begin,d,found=0;
	if(n>1)
	{
		for(int i=dif;i>0;i--)
		{
			if(found) break;
			for(int j=size-1;j>0;j--)
			{
				int cnt=1,next=v[j]-i;
				while(p[next]==0&&next>=2)
				{
					cnt++;
					next-=i;
				}
				if(cnt>=n)
				{
					d=i;
					begin=v[j]-d*(n-1);
					found=1;
					break;
				}
			}
		}
	}
	if(found)
	{
		cout<<begin;
		for(int i=1;i<n;i++)
			cout<<" "<<begin+i*d;
		cout<<endl;
	}
	else
	{
		for(int i=m;i>=2;i--)
			if(!p[i])
			{
				cout<<i<<endl;
				break;
			}
	}
	return 0;
}

7-2 Lab Access Scheduling (25 分) 区间贪心

【解题思路】

区间贪心模板题。

我们使用结构体存储每个人开始和结束时间,按照结束时间从早到晚排序。从前往后遍历一遍,如果时间不重叠,贪心选择结束时间最早的即可。

【满分代码】

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct node
{
	int begin,end;
	bool operator < (const node b) const
	{
		return end<b.end;
	}
}p[2005];
int main()
{
	int n,h,m,s,ans=1;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d:%d:%d",&h,&m,&s);
		p[i].begin=h*3600+m*60+s;
		scanf("%d:%d:%d",&h,&m,&s);
		p[i].end=h*3600+m*60+s;
	}
	sort(p,p+n);
	//for(int i=0;i<n;i++)
	//	cout<<p[i].end<<endl;
	int sta=p[0].end;
	for(int i=1;i<n;i++)
	{
		if(p[i].begin>=sta)
		{
			ans++;
			sta=p[i].end;
		}
	}
	cout<<ans<<endl;
	return 0;
}

7-3 Structure of Max-Heap (25 分) 最大堆

【解题思路】

按照输入,将数字逐个加入最大堆中,并对堆进行调整。完成建堆以后,用一个map存储各数字在堆中的位置(数组下标),以供后面查询。

下面输入每行字符串,这里处理比较巧妙,逐个单词输入,并不需要用到复杂的字符串处理。具体看代码实现,每部分加上了注释,代表是五种查询中的哪一种,然后通过map找到数字对应的数组下标,判断是否符合,输出结果即可。

【满分代码】

#include <iostream>
#include <cstdio>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); 
	int n,m,a,b,d[1005];
	string x,y,z,s,t;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>d[i];
		for(int j=i;j>1;j/=2)
		{
			if(d[j]>d[j/2])
				swap(d[j],d[j/2]);
			else
				break;
		}
	}//建最大堆 
	map<int,int> pos;
	for(int i=1;i<=n;i++)
		pos[d[i]]=i;//记录各数字在堆中的位置 
	while(m--)
	{
		cin>>a>>x;
		if(x=="and")//a和b是否为兄弟结点 
		{
			cin>>b>>y>>z;
			if(pos[a]==0||pos[b]==0||pos[a]==pos[b])//结点a或b不存在,或者a和b是同一个结点 
			{
				cout<<"0";
				continue;
			}
			if(pos[a]/2==pos[b]/2)
				cout<<"1";
			else
				cout<<"0";
		}
		else//(x=="is") 
		{
			cin>>y>>z;
			if(z=="root")//a是否为根节点 
			{
				if(pos[a]==1)
					cout<<"1";
				else
					cout<<"0";
			}
			else if(z=="parent")//a是否为b的父亲结点 
			{
				cin>>s>>b;
				if(pos[a]==0||pos[b]==0)
				{
					cout<<"0";
					continue;
				}
				if(pos[a]==pos[b]/2)
					cout<<"1";
				else
					cout<<"0";
			}
			else if(z=="left")//a是否为b的左子结点 
			{
				cin>>s>>t>>b;
				if(pos[a]==0||pos[b]==0)
				{
					cout<<"0";
					continue;
				}
				if(pos[a]==pos[b]*2)
					cout<<"1";
				else
					cout<<"0";
			}
			else if(z=="right")//a是否为b的右子结点 
			{
				cin>>s>>t>>b;
				if(pos[a]==0||pos[b]==0)
				{
					cout<<"0";
					continue;
				}
				if(pos[a]==pos[b]*2+1)
					cout<<"1";
				else
					cout<<"0";
			}
		}
	}
	return 0;
}

7-4 Recycling of Shared Bicycles (30 分) Floyd+DFS

【解题思路】

这道题是一个简单的图论问题,一共有从0到n编号的点,其中0是出发点。要求每次到达距离最短的下一个点(如果距离相等则编号小的点优先),最后输出访问路径。如果所有点都能访问到,输出路径长度之和;否则输出不能访问到的点。

n最大为200,数据范围不大,我们使用邻接矩阵存图。使用Floyd更新每两个点之间的最短路径长度。

从0结点出发,通过DFS记录每个点的访问情况和访问路径即可。

【满分代码】

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int INF=1000000000;
int n,m,G[205][205],vis[205],ans=0;
vector<int> vec;//存储访问路径 
void dfs(int pos,int temp)
{
	if(vec.size()==n)//1-n都已访问过 
	{
		ans=temp;
		return;
	}
	int minpos=0,mindis=INF,flag=0;
	for(int i=0;i<=n;i++)
	{
		if(!vis[i])
			if(G[pos][i]<mindis)
			{
				flag=1;
				mindis=G[pos][i];
				minpos=i;
			}
	}//找到最短距离的点(距离相同时编号小的点优先) 
	if(!flag) return;//没有点可以访问 
	vis[minpos]=1;
	vec.emplace_back(minpos);
	dfs(minpos,temp+mindis);//访问下一个点 
}
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	int a,b,c;
	for(int i=0;i<=n;i++)
	for(int j=0;j<=n;j++)
	{
		if(i==j)
			G[i][j]=0;
		else
			G[i][j]=INF;
	}//邻接矩阵初始化 
	for(int i=0;i<m;i++)
	{
		cin>>a>>b>>c;
		G[a][b]=G[b][a]=c;
	}//输入图 
	for(int i=0;i<=n;i++)
	for(int j=0;j<=n;j++)
	for(int k=0;k<=n;k++)
		if(G[i][k]+G[k][j]<G[i][j])
			G[i][j]=G[i][k]+G[k][j];//Floyd最短路更新 
	vis[0]=1;
	dfs(0,0);//从0点出发开始访问 
	cout<<"0";
	for(int i=0;i<vec.size();i++)
		cout<<" "<<vec[i];
	cout<<endl;//输出路径 
	if(vec.size()==n)
		cout<<ans<<endl;//如果所有点都访问过,输出路径长度之和 
	else
	{
		int flag=1;
		for(int i=0;i<=n;i++)
			if(!vis[i])
			{
				if(flag)
				{
					cout<<i;
					flag=0;
				}
				else
					cout<<" "<<i;
			}
	}//输出未访问到的点 
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

球王武磊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值