【PAT】2019年甲级秋季考试答案

PAT2019年甲级秋季考试答案


7-1 Forever (20 分)
思路:
由于在考场上没有完全AC,此处参考了 @Steven 周的思路。

首先考虑数字num末位不是9的情况,num的各位之和为m,num+1的各位之和为n,显然num+1只是在末位加1,不会产生进位,那么n=m+1,根据我们的数学常识,两个相差1的数最大公约数只能为1,不符合题目要求的“最大公约数是大于2的素数”。

因此看来上述情况不可行,我们在遍历时只需要考虑num尾数为9的情况,例如要求num位数为5时,只需要遍历10009,10019,10029…99999即可,时间复杂度直线下降,避免了超时。

本题还有一个需要注意的点是,要求以n增序的序列输出,因此每次找到符合要求的num之后把对应的n和num一起放入set,等本次遍历结束之后统一输出。

代码如下:

#include 
#include 
#include 
using namespace std;

bool isPrime(int num){
    if(num<=2) return false;
    for(int i=2;i<=sqrt(num);i++){
        if(num%i==0) return false;
    }
    return true;
}
int gcd(int a,int b){
    if(b==0) return a;
    else return gcd(b,a%b);
}

int getTotal(int num){
    int total=0;
    while(num>0){
        total+=num%10;
        num/=10;
    }
    return total;
}
int main(){
    int N,k,m,n;
    cin>>N;
    for(int i=1;i<=N;i++){
        cout<<"Case "<>k>>m;
        set >ans;
        int num=1;
        for(int j=1;j<=k-2;j++){
            num*=10;
        }
        for(int j=num;j<10*num;j++){
            int res=j*10+9;
            if(getTotal(res)==m){
                n=getTotal(res+1);
                int g=gcd(m,n);
                if(isPrime(g)){
                   ans.insert(make_pair(n,res));
                }
            }
        }
        if(ans.size()==0){
            cout<<"No Solution"<first<<" "<second<

7-2 Merging Linked Lists (25 分)

代码如下:

#include 
#include 
#include 
using namespace std;
const int maxn=1000000;
struct Node{
    int address,data,next;
}node[maxn];
vector list1,list2;
int begin1,begin2,n;
int main(){
    cin>>begin1>>begin2>>n;
    int address;
    for(int i=0;i>address;
        cin>>node[address].data>>node[address].next;
        node[address].address=address;
    }
    for(int now=begin1;now!=-1;now=node[now].next){
        list1.push_back(node[now]);
    }
    for(int now=begin2;now!=-1;now=node[now].next){
        list2.push_back(node[now]);
    }
    if(list2.size()>=2*list1.size()){
        vector tmp;
        tmp=list2;
        list2=list1;
        list1=tmp;
    }
    vector res;
    
    for(int i=0,j=list2.size()-1;;){
        if(i=0) res.push_back(list2[j--]);
        if(i>=list1.size() && j<0) break;
    }
    int i=0;
    for(;i

7-3 Postfix Expression (25 分)

Tips:
后序遍历时,如果遇到当前结点的左子树为空,右子树非空的情况,需要先输出当前结点,再递归遍历右子树。这种特殊处理对应于运算数前有符号的情况,例如样例中的-b。
除此之外只需要建立静态树,进行常规的后续遍历即可。

代码如下:

#include 
using namespace std;
const int maxn=22;
struct Node{
    string data;
    int left,right;
}node[maxn];
bool notRoot[maxn]={false};

void preTravel(int u){
    if(u==-1) return;
    if(node[u].left==-1 && node[u].right!=-1){
        cout<<"(";
        cout<>n;
    for(int i=1;i<=n;i++){
        cin>>node[i].data;
        cin>>node[i].left>>node[i].right;
        if(node[i].left!=-1) notRoot[node[i].left]=true;
        if(node[i].right!=-1) notRoot[node[i].right]=true;
    }
    int i;
    for(i=1;i<=n;i++){
        if(notRoot[i]==false){
            break;
        }
    }
    preTravel(i); //i=root index
    return 0;
}

7-4 Dijkstra Sequence (30 分)

Dijkstra’s algorithm is one of the very famous greedy algorithms. It is used for solving the single source shortest path problem which gives the shortest paths from one particular source vertex to all the other vertices of the given graph. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later.

In this algorithm, a set contains vertices included in shortest path tree is maintained. During each step, we find one vertex which is not yet included and has a minimum distance from the source, and collect it into the set. Hence step by step an ordered sequence of vertices, let’s call it Dijkstra sequence, is generated by Dijkstra’s algorithm.

On the other hand, for a given graph, there could be more than one Dijkstra sequence. For example, both { 5, 1, 3, 4, 2 } and { 5, 3, 1, 2, 4 } are Dijkstra sequences for the graph, where 5 is the source. Your job is to check whether a given sequence is Dijkstra sequence or not.

解题思路:

这道题考察的是传统Dijkstra算法,但是和以往求最短路径、最短时长的考察方法有一点差别,是要求判断给定的路径是否为合法的Dijkstra路径。受以往此类题目做题方法的影响,大家对这道题很容易产生的第一反应是先根据给定起点进行Dijkstra遍历,把每个顶点可能的前驱顶点存储在vector数组中,再从给定的路径终点同时逆推数组和路径看两者是否相符。
但这道题的解法事实上没有那么复杂。只需要按照正常Dijkstra算法的流程走,并且不需要记录前驱顶点,只需要在每次循环中寻找dis[j]最小的结点时,判断找到的结点是否与给定路径下相应的结点相同。(即给定序列对应的顶点是否是当前可选的最佳顶点)
考虑到每次距离最小的顶点可能不止一个,因此只需判断找到的mind与dis[path[i]]是否相等,如果不相等则说明序列错误,返回false,如果相等则将找到的最近顶点u换成对应的path[i],再在最近顶点的基础上进行惯例的优化,直到遍历到给定序列的终点,始终一致则返回true。

代码如下:

#include 
using namespace std;
const int maxn=1010;
const int INF=1000000000;
int G[maxn][maxn];
int dis[maxn];
int path[maxn];
bool vis[maxn]={false};
int n,m;
bool Dijkstra(int st){
    fill(vis,vis+maxn,false);
    fill(dis,dis+maxn,INF);
    dis[st]=0;
    for(int i=0;i>n>>m;
    fill(G[0],G[0]+maxn*maxn,INF);
    int a,b;
    for(int i=0;i>a>>b;
        cin>>G[a][b];
        G[b][a]=G[a][b];
    }
    int k;
    cin>>k;
    for(int i=0;i>path[j];
        }
        int st=path[0];
        if(Dijkstra(st)) cout<<"Yes"<

你可能感兴趣的:(【PAT】2019年甲级秋季考试答案)