公众号题解在此
题目在此
因为某些原因没有报名这次的PAT甲级考试, 所以在上班时间摸鱼写了一下😂 已投稿,等小拼姐发了 拼题A 公众号我马上发博客😂 2022.6.7
2022.6.10
等了一周,小拼姐终于发公众号了。。。 我终于可以发博客了。。。 关注 拼题A 公众号也可以查看 2022.6.13
7-1 What Day is Today
题目大意: 给出两个孩子说的昨天、今天和明天分别是星期几,每个孩子有且仅有其中一个说的是正确的。
解题思路: 枚举周日到周六,分别判断两个孩子说正确的个数,如果两个孩子分别有一个正确的,则是答案。
代码:
#include <bits/stdc++.h>
using namespace std;
int pre[7]={6,0,1,2,3,4,5},next[7]={1,2,3,4,5,6,0},a[3],b[3];
string day[3]={"yesterday","today","tomorrow"};
string week[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
int main()
{
cin>>a[0]>>a[1]>>a[2]>>b[0]>>b[1]>>b[2];
for(int i=0;i<7;i++)
{
int c1=0,c2=0,r1,r2;
if(a[0]==pre[i])c1++,r1=0;
if(a[1]==i)c1++,r1=1;
if(a[2]==next[i])c1++,r1=2;
if(b[0]==pre[i])c2++,r2=0;
if(b[1]==i)c2++,r2=1;
if(b[2]==next[i])c2++,r2=2;
if(c1==1&&c2==1)
{
cout<<week[i]<<endl<<day[r1]<<endl<<day[r2]<<endl;
break;
}
}
return 0;
}
7-2 Least Recently Used Cache
题目大意: 给出缓存大小n和数据,依据最近最少使用(即最长时间没有被使用过)原则,依次输出从缓存中删除的数据。
解题思路: 依次往队列中插入数据,记录队列里不重复数据的个数c以及每个数据的个数num[i]。如果c大于n,则让队首元素出队,如果队首元素的数据在队内大于一个,就说明之后这个数据又被调用过,则让下一个元素出队,直到出队的元素在队内只存在这一个。依次保存在队内只存在一个的出队元素,最后输出。
代码:
#include <bits/stdc++.h>
using namespace std;
int v[20010],num[20010],c,n,m;
queue<int>q;
vector<int>r;
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int x;
scanf("%d",&x);
if(c<n)
{
q.push(x);
if(num[x]==0)
{
c++;
}
num[x]++;
}
else
{
if(num[x]==0)
{
while(num[q.front()]!=1)
{
num[q.front()]--;
q.pop();
}
num[q.front()]--;
r.push_back(q.front());
q.pop();
}
q.push(x);
num[x]++;
}
}
for(auto i=r.begin();i!=r.end();i++)
{
if(i!=r.begin())printf(" ");
printf("%d",*i);
}
return 0;
}
PS:我一开始想到的是优先队列,把<i, num[i]>存到优先队列中。但是写完仔细一想,i本来就是按顺序的啊,直接用普通队列不就可以了吗。。。附上优先队列的代码。。。
#include <bits/stdc++.h>
using namespace std;
int v[20010],num[20010],c,n,m;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
vector<int>r;
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int x;
scanf("%d",&x);
if(c<n)
{
q.push({i,x});
if(num[x]==0)
{
c++;
}
num[x]++;
}
else
{
if(num[x]==0)
{
c++;
auto t=q.top();
while(num[t.second]!=1)
{
num[t.second]--;
q.pop();
t=q.top();
}
num[t.second]--;
r.push_back(q.top().second);
q.pop();
c--;
}
q.push({i,x});
num[x]++;
}
}
for(auto i=r.begin();i!=r.end();i++)
{
if(i!=r.begin())printf(" ");
printf("%d",*i);
}
return 0;
}
7-3 DFS Sequence
题目大意: 给出一个有向图,和k个序列,判断序列是不是DFS序列。
解题思路: 先将序列中的元素依次入队列,使用深度优先搜索,从队列的第一个元素开始搜索。
- 如果当前结点能到队列里的下一个结点,则继续搜索下一个结点;
- 如果不能到达队列里的下一个结点:
a. 如果当前结点能够到达其他结点,则不是DFS序列; b. 如果不能到达其他结点,则回溯,返回到上一个结点继续搜索。
PS:第一次写这题的时候,几分钟写完提交就AC了,dfs函数里的while(!q.empty())我是没有写的,直接就是if else。AC完仔细一想,我的代码不对啊,我的代码没有考虑回溯到中间结点继续搜索的情况,每次都是回溯到底继续搜索队列里的下一个结点,题目的测试数据不太全面,我构造的下面这组数据我的第一份代码都是过不去的。
5 4 1
1 2
1 5
2 3
2 4
1 2 3 5 4
到3搜不下去应该回溯到2继续搜索4,深度优先,而不是回溯到底的1继续搜索5,应该输出 no 但是输出了 yes 。顺便搜了一下网上已经存在的几篇题解,绝大多数的代码都过不去这组数据。
正确代码如下:
#include <bits/stdc++.h>
using namespace std;
int n,m,k,a[1010][1010],vis[1010],flag=1;
vector<int>vec[1010];
queue<int>q;
set<int>s;
void dfs(int x)
{
if(flag==0||q.empty())return;
vis[x]=1;
while(!q.empty())
{
if(a[x][q.front()]==1)
{
int y=q.front();
q.pop();
dfs(y);
}
else
{
for(int i=0;i<vec[x].size();i++)
{
if(vis[vec[x][i]]==0)
{
flag=0;
return;
}
}
return;
}
}
}
int main()
{
cin>>n>>m>>k;
while(m--)
{
int x,y;
cin>>x>>y;
a[x][y]=1;
vec[x].push_back(y);
}
while(k--)
{
memset(vis,0,sizeof vis);
flag=1;
while(!q.empty())q.pop();
s.clear();
for(int i=0;i<n;i++)
{
int x;
cin>>x;
q.push(x);
s.insert(x);
}
while(!q.empty())
{
int y=q.front();
q.pop();
dfs(y);
}
if(flag==0||s.size()!=n)cout<<"no"<<endl;
else cout<<"yes"<<endl;
}
return 0;
}
7-4 Complete D-Tree
题目大意: 给出度数为d的完全树的前序遍历,输出层序遍历,以及给出的结点到根节点的路径。
解体思路: 使用深度优先搜索保存层序遍历,之后根据 父节点编号 = (子结点编号 - 1) / 度数 求出结点到根节点的路径。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,d,le[55],pre[55],p=0,k;
void dfs(int x)
{
if(x>=n)return;
le[x]=pre[p++];
for(int i=1;i<=d;i++)
{
dfs(x*d+i);
}
}
int main()
{
cin>>n>>d;
for(int i=0;i<n;i++)cin>>pre[i];
dfs(0);
for(int i=0;i<n;i++)cout<<le[i]<<(i<n-1?" ":"\n");
cin>>k;
while(k--)
{
int x;
cin>>x;
while(x)
{
cout<<le[x]<<" ";
x=(x-1)/d;
}
cout<<le[0]<<endl;
}
return 0;
}
|