PAT(甲级)2019年冬季考试

7-1 Good in C (20 分)

时间限制:400 ms 内存限制:64 MB

When your interviewer asks you to write "Hello World" using C, can you do as the following figure shows?

HWC.jpg

Input Specification:

Each input file contains one test case. For each case, the first part gives the 26 capital English letters A-Z, each in a 7×5 matrix of C's and .'s. Then a sentence is given in a line, ended by a return. The sentence is formed by several words (no more than 10 continuous capital English letters each), and the words are separated by any characters other than capital English letters.

It is guaranteed that there is at least one word given.

Output Specification:

For each word, print the matrix form of each of its letters in a line, and the letters must be separated by exactly one column of space. There must be no extra space at the beginning or the end of the word.

Between two adjacent words, there must be a single empty line to separate them. There must be no extra line at the beginning or the end of the output.

Sample Input:

..C..
.C.C.
C...C
CCCCC
C...C
C...C
C...C
CCCC.
C...C
C...C
CCCC.
C...C
C...C
CCCC.
.CCC.
C...C
C....
C....
C....
C...C
.CCC.
CCCC.
C...C
C...C
C...C
C...C
C...C
CCCC.
CCCCC
C....
C....
CCCC.
C....
C....
CCCCC
CCCCC
C....
C....
CCCC.
C....
C....
C....
CCCC.
C...C
C....
C.CCC
C...C
C...C
CCCC.
C...C
C...C
C...C
CCCCC
C...C
C...C
C...C
CCCCC
..C..
..C..
..C..
..C..
..C..
CCCCC
CCCCC
....C
....C
....C
....C
C...C
.CCC.
C...C
C..C.
C.C..
CC...
C.C..
C..C.
C...C
C....
C....
C....
C....
C....
C....
CCCCC
C...C
C...C
CC.CC
C.C.C
C...C
C...C
C...C
C...C
C...C
CC..C
C.C.C
C..CC
C...C
C...C
.CCC.
C...C
C...C
C...C
C...C
C...C
.CCC.
CCCC.
C...C
C...C
CCCC.
C....
C....
C....
.CCC.
C...C
C...C
C...C
C.C.C
C..CC
.CCC.
CCCC.
C...C
CCCC.
CC...
C.C..
C..C.
C...C
.CCC.
C...C
C....
.CCC.
....C
C...C
.CCC.
CCCCC
..C..
..C..
..C..
..C..
..C..
..C..
C...C
C...C
C...C
C...C
C...C
C...C
.CCC.
C...C
C...C
C...C
C...C
C...C
.C.C.
..C..
C...C
C...C
C...C
C.C.C
CC.CC
C...C
C...C
C...C
C...C
.C.C.
..C..
.C.C.
C...C
C...C
C...C
C...C
.C.C.
..C..
..C..
..C..
..C..
CCCCC
....C
...C.
..C..
.C...
C....
CCCCC
HELLO~WORLD!

Sample Output:

C...C CCCCC C.... C.... .CCC.
C...C C.... C.... C.... C...C
C...C C.... C.... C.... C...C
CCCCC CCCC. C.... C.... C...C
C...C C.... C.... C.... C...C
C...C C.... C.... C.... C...C
C...C CCCCC CCCCC CCCCC .CCC.

C...C .CCC. CCCC. C.... CCCC.
C...C C...C C...C C.... C...C
C...C C...C CCCC. C.... C...C
C.C.C C...C CC... C.... C...C
CC.CC C...C C.C.. C.... C...C
C...C C...C C..C. C.... C...C
C...C .CCC. C...C CCCCC CCCC.

解析:

读入一行用getline,用STL把各个字符的矩阵存下来。分析字符串时,遇到大写字母先不输出,而是记住起点,遇到非大写字母再一口气输出。

#include <vector>
#include <map>
#include <iostream>
using namespace std;

map<char, vector<string>> letters;  // 存储各字符的矩阵

void print (string s) {
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < s.length(); j++) {
            printf("%s", letters[s[j]][i].c_str());
            if (j < s.length() - 1) printf(" ");
        }
        printf("
");
    }
}

void test() {
    int i, j;
    char l;
    string s;
    for (l = 'A'; l <= 'Z'; l++) {
        for (j = 0; j < 7; j++) {
            getline(cin, s);
            letters[l].push_back(s);
        }
    }
    getline(cin, s);
    int start = -1, count = 0;
    for (i = 0; i < s.length(); i++) {
        // 遇到大写字母:先不输出,标定起点
        if (s[i] >= 'A' && s[i] <= 'Z') {
            if (start == -1) start = i;
        } else {  // 遇到非大写字母,一口气输出
            if (start != -1) {
                if (count > 0) printf("
");
                print(s.substr(start, i - start));
                count++;
                start = -1;
            }
        }
    }
    if (start != -1) {
        if (count > 0) printf("
");
        print(s.substr(start, i - start));
    }
}

int main() {
    test();
    return 0;
}

7-2 Block Reversing (25 分)

时间限制:400 ms 内存限制:64 MB

Given a singly linked list L. Let us consider every K nodes as a block (if there are less than K nodes at the end of the list, the rest of the nodes are still considered as a block). Your job is to reverse all the blocks in L. For example, given L as 1→2→3→4→5→6→7→8 and K as 3, your output must be 7→8→4→5→6→1→2→3.

Input Specification:

Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤105) which is the total number of nodes, and a positive K (≤N) which is the size of a block. The address of a node is a 5-digit nonnegative integer, and NULL is represented by −1.

Then N lines follow, each describes a node in the format:

Address Data Next

where Address is the position of the node, Data is an integer, and Next is the position of the next node.

Output Specification:

For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:

00100 8 3
71120 7 88666
00000 4 99999
00100 1 12309
68237 6 71120
33218 3 00000
99999 5 68237
88666 8 -1
12309 2 33218

Sample Output:

71120 7 88666
88666 8 00000
00000 4 99999
99999 5 68237
68237 6 00100
00100 1 12309
12309 2 33218
33218 3 -1

解析:

又是静态链表题,按套路:先在链表的结构体里加一个index参数并初始化为一个很大的数,再对链表按要求进行遍历, 并修改结点的index,最后将所有结点按index排序。既然链表要倒过来,干脆先遍历一遍,把链表的各结点地址都放到vector里。输出地址记得用%05d,但是-1要单独输出。

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;

const int maxn = 100000;

typedef struct Node {
    int data, address, next, index = 0x3fffffff;
} Node;
Node nodes[maxn];
vector<int> link;

bool cmp (Node a, Node b) {
    return a.index < b.index;
}

void test() {
    int root, n, k;
    int i, j, t1, t2, t3;
    scanf("%d %d %d", &root, &n, &k);
    for (i = 0; i < n; i++) {
        scanf("%d %d %d", &t1, &t2, &t3);
        nodes[t1].address = t1; nodes[t1].data = t2; nodes[t1].next = t3;
    }
    i = root;
    // 把链表的各结点地址都放到vector里
    while (i != -1) {
        link.push_back(i);
        i = nodes[i].next;
    }
    int blocks = link.size() / k;
    int index = 0;
    // 处理尾巴
    for (i = blocks * k; i < link.size(); i++, index++) {
        nodes[link[i]].index = index;
    }
    // 每K个逆转
    for (i = blocks - 1; i >= 0; i--) {
        for (j = i * k; j < i * k + k; j++, index++) {
            nodes[link[j]].index = index;
        }
    }
    sort(nodes, nodes + maxn, cmp);
    for (i = 0; i < (int)link.size() - 1; i++) {
        printf("%05d %d %05d
", nodes[i].address, nodes[i].data, nodes[i+1].address);
    }
    printf("%05d %d -1", nodes[i].address, nodes[i].data);
}

int main() {
    test();
    return 0;
}

7-3 Summit (25 分)

时间限制:400 ms 内存限制:64 MB

A summit (峰会) is a meeting of heads of state or government. Arranging the rest areas for the summit is not a simple job. The ideal arrangement of one area is to invite those heads so that everyone is a direct friend of everyone.

Now given a set of tentative arrangements, your job is to tell the organizers whether or not each area is all set.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers N (≤ 200), the number of heads in the summit, and M, the number of friendship relations. Then M lines follow, each gives a pair of indices of the heads who are friends to each other. The heads are indexed from 1 to N.

Then there is another positive integer K (≤ 100), and K lines of tentative arrangement of rest areas follow, each first gives a positive number L (≤ N), then followed by a sequence of L distinct indices of the heads. All the numbers in a line are separated by a space.

Output Specification:

For each of the K areas, print in a line your advice in the following format:

  • if in this area everyone is a direct friend of everyone, and no friend is missing (that is, no one else is a direct friend of everyone in this area), print Area X is OK..
  • if in this area everyone is a direct friend of everyone, yet there are some other heads who may also be invited without breaking the ideal arrangement, print Area X may invite more people, such as H. where H is the smallest index of the head who may be invited.
  • if in this area the arrangement is not an ideal one, then print Area X needs help. so the host can provide some special service to help the heads get to know each other.

Here X is the index of an area, starting from 1 to K.

Sample Input:

8 10
5 6
7 8
6 4
3 6
4 5
2 3
8 2
2 7
5 3
3 4
6
4 5 4 3 6
3 2 8 7
2 2 3
1 1
2 4 6
3 3 2 1

Sample Output:

Area 1 is OK.
Area 2 is OK.
Area 3 is OK.
Area 4 is OK.
Area 5 may invite more people, such as 3.
Area 6 needs help.

解析:

题目大意:有一群人,其中有些人互相认识,是朋友。现在从这些人中抽出几个人组成一个小组,判断是哪种小组:

Area X is OK.组里所有人相互认识,并且这些人没有其他共同的朋友。

Area X may invite more people, such as H.所有人相互认识,但是还有共同的朋友可以拉进组,例如H。如果有多个,取序号最小的。

Area X needs help.组里有人相互不认识,X是组号。

用邻接表保存这张无向图,对每个小组,如果所有人相互认识,这个小组应该对应一张完全图,即每个人的度都等于小组人数-1。如果组外还有熟人,这个熟人应该有等同于小组人数的边连接到小组里。

注:这道题和【A1142 Maximal Clique】相似,都是用数组保存无向图每个结点的度。

#include <vector>
#include <set>
#include <iostream>
using namespace std;

const int maxn = 202;

vector<int> G[maxn];

void test() {
    int n, m, K, l;
    int i, j, k, t1, t2;
    scanf("%d %d", &n, &m);
    for (i = 0; i < m; i++) {
        scanf("%d %d", &t1, &t2);
        G[t1].push_back(t2); G[t2].push_back(t1);
    }
    scanf("%d", &K);
    for (i = 1; i <= K; i++) {
        scanf("%d", &l);
        vector<int> count(n+1);  // count记录各结点关于组内人的度
        set<int> input;  // 记录组里每个人
        for (j = 0; j < l; j++) {
            scanf("%d", &t1);
            input.insert(t1);
            // item为此人的各个朋友
            for (int item : G[t1]) count[item]++;
        }
        int flag = 0;
        // 判断组内人是否组成完全图
        for (int item : input) {
            if (count[item] + 1 != l) {
                flag = 1; break;
            }
        }
        if (flag) {
            printf("Area %d needs help.
", i);
            continue;
        }
        flag = 0;
        // 判断组外人是否有等同于小组人数的边连接到小组里
        for (j = 1; j <= n; j++) {
            if (!input.count(j) && count[j] == l) {
                printf("Area %d may invite more people, such as %d.
", i, j);
                flag = 1; break;
            }
        }
        if (flag == 0) printf("Area %d is OK.
", i);
    }
}

int main() {
    test();
    return 0;
}

7-4 Cartesian Tree (30 分)

时间限制:400 ms 内存限制:64 MB

A Cartesian tree is a binary tree constructed from a sequence of distinct numbers. The tree is heap-ordered, and an inorder traversal returns the original sequence. For example, given the sequence { 8, 15, 3, 4, 1, 5, 12, 10, 18, 6 }, the min-heap Cartesian tree is shown by the figure.

CTree.jpg

Your job is to output the level-order traversal sequence of the min-heap Cartesian tree.

Input Specification:

Each input file contains one test case. Each case starts from giving a positive integer N (≤30), and then N distinct numbers in the next line, separated by a space. All the numbers are in the range of int.

Output Specification:

For each test case, print in a line the level-order traversal sequence of the min-heap Cartesian tree. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the beginning or the end of the line.

Sample Input:

10
8 15 3 4 1 5 12 10 18 6

Sample Output:

1 3 5 8 4 6 15 10 12 18

解析:

类似于用前序+中序建树的思路,对小根堆而言,中序序列中的最小值是父结点,分割的两个序列分别是左子树和右子树,以此类推。

#include <vector>
#include <queue>
#include <iostream>
using namespace std;

typedef struct Node {
    int data;
    struct Node *l = NULL, *r = NULL;
} Node;

int n;
vector<int> input;
Node *root = NULL;

Node* create (int left, int right) {
    if (left > right) return NULL;
    int min_index = left, min_data = input[left], i;
    // 找出序列中最小值
    for (i = left + 1; i <= right; i++) {
        if (min_data > input[i]) {
            min_data = input[i]; min_index = i;
        }
    }
    Node *node = new Node; node->data = min_data;
    node->l = create(left, min_index - 1);
    node->r = create(min_index + 1, right);
    return node;
}

void BFS () {
    int count = 0;
    queue<Node*> q;
    q.push(root);
    while (!q.empty()) {
        Node *node = q.front(); q.pop();
        printf("%d", node->data); count++;
        if (count < n) printf(" ");
        if (node->l != NULL) q.push(node->l);
        if (node->r != NULL) q.push(node->r);
    }
}

void test() {
    int i;
    scanf("%d", &n);
    input.resize(n);
    for (i = 0; i < n; i++) scanf("%d", &input[i]);
    root = create(0, n - 1);
    BFS();
}

int main() {
    test();
    return 0;
}

总结

编号 标题 分数 类型
7-1 Good in C 20 3.3 图形输出
7-2 Block Reversing 25 7.3 链表处理
7-3 Summit 25 10.2 图的存储
7-4 Cartesian Tree 30 9.2 二叉树的遍历

按通过率来看,难度为:第一题>第二题>第三题>第四题。第一题难在怎么把每张图存下来,以及怎么给字符串分行。第二题又又是链表题,采用与当年秋第二题相似的思路。第三题和题库里某道题类似。第四题没见过,不过可以观察出来建树的方法类似于学过的前序+中序建树。这道题通过率超过一半,可见大家的观察能力都很强(。总体上这次考试不难,当年最难的毫无疑问就是秋。

原文地址:https://www.cnblogs.com/jushou233/p/14628685.html