2019秋季PAT甲级题解(无第一题)
今年的2、3、4题比较简单,尴尬的是第1题一点思路都没有,甚至没想起用暴力求解得点分,是这次PAT很大的遗憾。
我把考试时候的代码贴在下面,本人代码水平并不高,贴出来只为学习交流,不喜勿喷~
7-2 Merging Linked Lists (25 分)
思路:先区分长链短链,然后不断循环,依次取长链中两个点和短链中一个点加入到新链中,直到长链和短链都处理完。
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> using namespace std; const int maxn=100010; int n,m1,m2,k; int f1,f2; vector<int>v[3],ans; struct node{ int Address ,Data ,Next; }nodes[maxn]; void merge(int a,int b){//合并过程,此时满足a>b int k1=0; int k2=0; int len2=v[b].size()-1; while(k1<v[a].size()||k2<v[b].size()){//若还有一个链没处理完 if(k1<v[a].size()){ //将长链第一个点加到ans中 ans.push_back(v[a][k1]); k1++; } if(k1<v[a].size()){ //将长链第二个点加到ans中 ans.push_back(v[a][k1]); k1++; } if(k2<v[b].size()){ //将短链的一个点加到ans中 ans.push_back(v[b][len2-k2]); k2++; } } } int main(){ cin>>f1>>f2>>n; for(int i=0;i<n;++i){ int add; scanf("%d",&add); nodes[add].Address=add; scanf("%d%d",&nodes[add].Data,&nodes[add].Next); } int p1=f1;//遍历第一条链 while(p1!=-1){ m1++; v[1].push_back(p1); p1=nodes[p1].Next; } int p2=f2;//遍历第二条链 while(p2!=-1){ m2++; v[2].push_back(p2); p2=nodes[p2].Next; } if(m1>m2){//区分出长链与短链 merge(1,2); }else merge(2,1); for(int i=0;i<ans.size()-1;++i){ int u=ans[i]; printf("%05d %d %05d\n",nodes[u].Address,nodes[u].Data,nodes[ans[i+1]].Address); } int u=ans[ans.size()-1]; printf("%05d %d -1\n",nodes[u].Address,nodes[u].Data); return 0; }
7-3 Postfix Expression (25 分)
这个题我开始没仔细研读题目,直接按树的中序遍历方式进行输出,发现不对后按照例子对中序遍历进行修改,惊喜的是这样居然就能AC了。
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <string> using namespace std; const int maxn=25; int n,m1,m2,k; int father[maxn]; struct node{ string data; int lchild,rchild; }nodes[maxn]; void inorder(int root){ printf("("); if(nodes[root].rchild!=-1&&nodes[root].lchild==-1){ cout<<nodes[root].data; if(nodes[root].rchild!=-1){ inorder(nodes[root].rchild); } }else{ if(nodes[root].lchild!=-1){ inorder(nodes[root].lchild); } if(nodes[root].rchild!=-1){ inorder(nodes[root].rchild); } cout<<nodes[root].data; } printf(")"); } int findFather(int x){ while(x!=father[x]){ x=father[x]; } return x; } int main(){ cin>>n; for(int i=1;i<=n;++i){ father[i]=i; } for(int i=1;i<=n;++i){ string str; cin>>nodes[i].data; scanf("%d%d",&nodes[i].lchild,&nodes[i].rchild); father[nodes[i].lchild]=father[nodes[i].rchild]=i; } int root=findFather(1); inorder(root); return 0; }
7-4 Dijkstra Sequence (30 分)
我个人感觉这道题目出的比较好,dijkstra模板可能大家都理解了,那种固定的做题方式大家也都会,而这道题是考到了对模板的理解。
刚开始我走了很多歪路,(主要是受之前做题惯性思维的影响,还在用dij+dfs之类的,当然也可以解,但不是很正的思路)
思路:在dijkstra过程中,从所有优化好路径的点中取一个距离最小的点 u ,我们只需要判断所给出的例子中那一步的值可以不可取做u就可以了,若可以取则继续下一步判断,若不能取则直接判NO。能不能取做u的标准是,d[u]是不是当前的最小值之一。
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <string> using namespace std; const int maxn=10010; const int inf=0x3fffffff; int nv,ne; struct node{ int w,v; }; vector<node>graph[maxn]; int d[maxn]; vector<int>check; bool vis[maxn]; bool flag; int p; bool dijkstra2(int root){ fill(d,d+maxn,inf); fill(vis,vis+maxn,false); d[root]=0; for(int i=1;i<=nv;++i){ int MIN=inf,u=-1; for(int j=1;j<=nv;++j){//关键代码部分 if(vis[j]==false&&d[j]<MIN){ //出现最小值让u取为它 MIN=d[j]; u=j; } else if(vis[j]==false&&d[j]==MIN){ //出现等于最小值,而且u是查询的值 if(j==check[p])u=j; } } if(u!=check[p]||u==-1)return false; vis[u]=true; p++; if(p>=nv)return true; //关键部分代码结束 for(int j=0;j<graph[u].size();++j){ int v=graph[u][j].v; if(vis[v]==false&&d[u]+graph[u][j].w<d[v]){ d[v]=d[u]+graph[u][j].w; } } } } int main(){ cin>>nv>>ne; for(int i=0;i<ne;++i){ int a,b,d; scanf("%d%d%d",&a,&b,&d); node temp; temp.v=b; temp.w=d; graph[a].push_back(temp); temp.v=a; graph[b].push_back(temp); } int k; cin>>k; for(int i=0;i<k;++i){ check.clear(); check.resize(nv); for(int j=0;j<nv;++j){ scanf("%d",&check[j]); } flag=false; p=0; flag=dijkstra2(check[0]); if(flag)cout<<"Yes"<<endl; else{ cout<<"No"<<endl; } } return 0; }