浙江大學計算機與軟件學院2019年保研上機


7-1 Happy Numbers (20 分)

時間限制:400 ms 內存限制:64 MB

A happy number is defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits in base-ten, and repeat the process until the number either equals 1 (where it will stay), or it loops endlessly in a cycle that does not include 1. Those numbers for which this process ends in 1 are happy numbers and the number of iterations is called the degree of happiness, while those that do not end in 1 are unhappy numbers (or sad numbers). (Quoted from Wikipedia)

For example, 19 is happy since we obtain 82 after the first iteration, 68 after the second iteration, 100 after the third iteration, and finally 1. Hence the degree of happiness of 19 is 4.

On the other hand, 29 is sad since we obtain 85, 89, 145, 42, 20, 4, 16, 37, 58, and back to 89, then fall into an endless loop. In this case, 89 is the first loop number for 29.

Now your job is to tell if any given number is happy or not.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤100). Then N lines follow, each contains a positive integer (no more than 104) to be tested.

Output Specification:

For each given number, output in a line its degree of happiness if it is happy, or the first loop number if it is sad.

Sample Input:

3
19
29
1

Sample Output:

4
89
0

解析:

1、按照題目的要求一步步來即可。

2、判重用unordered_set,取各位的值既可以用10除取余,也可以轉成字符串。

#include <unordered_set>
#include <cmath>
#include <iostream>
using namespace std;

void test() {
    int n, number, degree, i, sum = 0;  // degree計快樂度
    string s;
    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        scanf("%d", &number);
        degree = 0;
        unordered_set<int> set;
        while (number != 1) {
            set.insert(number);
            sum = 0;
            for (auto item : to_string(number)) {
                sum += pow((item - 48), 2);
            }
            degree++;
            if (set.count(sum)) break;
            number = sum;
        }
        if (number == 1) printf("%d\n", degree);
        else printf("%d\n", sum);
    }
}

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

7-2 Zigzag Sequence (25 分)

時間限制:200 ms 內存限制:64 MB

This time your job is to output a sequence of N positive integers in a zigzag format with width M in non-decreasing order. A zigzag format is to fill in the first row with M numbers from left to right, then the second row from right to left, and so on and so forth. For example, a zigzag format with width 5 for numbers 1 to 13 is the following:

1 2 3 4 5
10 9 8 7 6
11 12 13

Input Specification:

Each input file contains one test case. For each case, the first line gives 2 positive integers N and M. Then the next line contains N positive integers as the original sequence. All the numbers are no more than 104. The numbers in a line are separated by spaces.

Output Specification:

For each test case, output the sequence in the zigzag format with width M in non-decreasing order. There must be exactly 1 space between two adjacent numbers, and no extra space at the beginning or the end of each line.

Sample Input 1:

14 5
37 76 98 20 98 76 42 53 99 95 60 81 58 93

Sample Output 1:

20 37 42 53 58
93 81 76 76 60
95 98 98 99

Sample Input 2:

15 4
96 37 76 98 20 98 76 42 53 99 95 60 81 58 93

Sample Output 2:

20 37 42 53
76 76 60 58
81 93 95 96
99 98 98

解析:

1、先求出一共要打印多少行。

2、根據當前行是奇數還是偶數,判斷要不要反過來打印,還要考慮當前行是否不足M個。

假設行i從0開始,則第i行的正向下標范圍是[i * M, i * M + M),因此反向打印的下標為[i * M + M, i * M]。再考慮到數組有上界,故正向時的范圍上界(開區間)應該在i * M + M與N中取較小值,反向時范圍下界(閉區間)應該在i * M + M與N - 1中取較小值。

3、打印每行時還要注意最后一個數字后不能帶空格。

4、也可以用reverse數組進行反轉,同樣要考慮數組上界。

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

void test() {
    int N, M, i, j, line;
    vector<int> input;
    vector<vector<int>> ans;
    scanf("%d %d", &N, &M);
    input.resize(N);
    line = N % M ? N / M + 1 : N / M;
    for (i = 0; i < N; i++) scanf("%d", &input[i]);
    sort(input.begin(), input.end());

    int start, end;
    for (i = 0; i < line; i++) {
        if (i % 2 == 0) {
            end = min(M + i * M, N);
            for (j = i * M; j < end; j++) {
                printf("%d", input[j]);
                if (j < end - 1) printf(" ");
            }
        } else {
            start = min(M - 1 + i * M, N - 1);
            for (j = start; j >= i * M; j--) {
                printf("%d", input[j]);
                if (j > i * M) printf(" ");
            }
        }
        printf("\n");
    }
}

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

7-3 Is It An AVL Tree (25 分)

時間限制:400 ms 內存限制:64 MB

In computer science, an AVL tree (Georgy Adelson-Velsky and Evgenii Landis' tree, named after the inventors) is a self-balancing binary search tree. It was the first such data structure to be invented. In an AVL tree, the heights of the two child subtrees of any node differ by at most one. (Quoted from wikipedia)

For each given binary search tree, you are supposed to tell if it is an AVL tree.

Input Specification:

Each input file contains several test cases. The first line gives a positive integer K (≤10) which is the total number of cases. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary search tree. The second line gives the preorder traversal sequence of the tree with all the keys being distinct. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in a line "Yes" if the given tree is an AVL tree, or "No" if not.

Sample Input:

3
7
50 40 36 48 46 62 77
8
50 40 36 48 46 62 77 88
6
50 40 36 48 46 62

Sample Output:

Yes
No
No

解析:

1、先用前序+中序建樹。

2、遞歸求出每個結點的左子樹和右子樹的高度。如果發現當前結點不平衡,就退出遞歸,不用判斷其它結點了;如果平衡,則當前結點的高度為左右子樹中較高的+1。

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

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

Node *root = NULL;
int N;
vector<int> pre, in;

Node *create (int pre1, int pre2, int in1, int in2) {
    if (pre1 > pre2) return NULL;
    int i = in1;
    while (in[i] != pre[pre1]) i++;
    int len = i - in1;
    Node *node = new Node;
    node->data = in[i];
    node->l = create(pre1 + 1, pre1 + len, in1, i - 1);
    node->r = create(pre1 + len + 1, pre2, i + 1, in2);
    return node;
}

int flag = 0;  // 當前樹是否AVL

int getHeight (Node *node) {
    // 當flag == 1時表示已經發現一個結點不平衡,沒有必要再判斷其它結點了
    if (flag == 1 || node == NULL) return 0;
    if (node->height == -1) {
        int left = getHeight(node->l);
        int right = getHeight(node->r);
        if (abs(left - right) > 1) {
            flag = 1;
            return 0;
        }
        node->height = max(left, right) + 1;
    }
    return node->height;
}

void test() {
    int K, i, j;
    scanf("%d", &K);
    for (i = 0; i < K; i++) {
        scanf("%d", &N);
        pre.clear(); pre.resize(N);
        for (j = 0; j < N; j++) scanf("%d", &pre[j]);
        in = pre;
        sort(in.begin(), in.end());
        root = create(0, N- 1, 0, N- 1);
        flag = 0;  // 假設是AVL樹,一旦發現有一個節點不是平衡的,就不是AVL樹
        getHeight(root);
        printf("%s\n", flag ? "No" : "Yes");
    }
}

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

7-4 Index of Popularity (30 分)

時間限制:1000 ms 內存限制:64 MB

The index of popularity (IP) of someone in his/her circle of friends is defined to be the number of friends he/she has in that circle. Now you are supposed to list the members in any given friend circle with top 3 IP's.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 2 positive integers N and M (both no more than 105), which are the total number of people and the number of friend relations, respectively. Hence the people here are numbered from 1 to N.

Then M lines follow, each contains the indices of a pair of friends, separated by a space. It is assumed that if A is a friend of B, then B is a friend of A.

Then several queries follow, each occupies a line. For each line of query, K (3≤KN), the total number of members in this friend circle is given first, with K indices of members follow. It is guaranteed that all the indices in a circle are distinct.

The input ends when K is zero, and this case must NOT be processed.

Output Specification:

For each query, print in a line the members with top 3 indices of popularity in descending order of their IP's. If there is a tie, output the one with the smaller number. The numbers must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.

Sample Input:

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

Sample Output:

3 1 4
1 3 2
2 4 7

解析:

麻煩的一題,容易超時,下一段是碎碎念,可以跳過不看:

105*105的鄰接矩陣太大了,只能用鄰接表。一開始鄰接表用unordered_set數組,對每個查詢集合Q,把Q里每個成員的聯系人從鄰接表里取出來形成一個S,再看看集合Q的其他人是否在S里,做法極其暴力,兩重循環+搜索,果然超時了,而且超時了2個6分的測試點。接着改進做法,既然要求兩個集合之交,先排序,兩個序列一起掃一遍就好了,線性復雜度。沒想到還是有一個超時。后來才觀察出來更簡單的做法。上網一搜題解,有人一下子就想到了這個方法,覺得這個題很簡單,我的內心是崩潰的……

方法一:對每個查詢集合Q,統計每個成員所有相連的另一個成員出現次數,然后只對Q包含的成員進行排序。

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

const int maxn = 100002;

typedef struct Node {
    int index, count;
} Node;

int N, M;
vector<int> G[maxn];

bool cmp (Node a, Node b) {
    if (a.count != b.count) return a.count > b.count;
    return a.index < b.index;
}

void test() {
    int i, t1, t2, K;
    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);
    while (K) {
        vector<Node> degree(K);
        for (i = 0; i < K; i++) {
            scanf("%d", &degree[i].index);
        }
        unordered_map<int, int> m;
        for (i = 0; i < K; i++) {
            vector<int> &temp = G[degree[i].index];
            for (auto item : temp) {
                m[item]++;
            }
        }
        for (auto &item : degree) {
            item.count = m[item.index];
        }
        sort(degree.begin(), degree.end(), cmp);
        for (i = 0; i < 2; i++) printf("%d ", degree[i].index);
        printf("%d\n", degree[i].index);
        scanf("%d", &K);
    }
}

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

方法二:存儲所有邊然后遍歷,若查詢集合Q中存在該邊,則兩端的結點的度都加1。

//
// Created by niko on 2020/9/19.
//
//剩余時間:19:44

#include <bits/stdc++.h>

using namespace std;
/**
 * 題意:給出n個點,m條邊的圖,接下來進行幾次查詢,每次查詢問由k個結點組成的子圖中
 * 前三個度數最高的結點編號(度數降序排序),若度數相同,則按照從小到大的順序輸出
 * @return
 */
vector<pair<int,int>> edge;//存儲每條邊
unordered_map<int,int> degree;//子圖中每個結點的度數
//排序規則
bool cmp(int a,int b){
    if(degree[a]!=degree[b])return degree[a]>degree[b];
    return a<b;
}
int main(){
    //加速cin
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,k,a,b;
    cin>>n>>m;
    while (m--){
        cin>>a>>b;
        edge.push_back({a,b});
    }
    while (cin>>k&&k!=0){
        degree.clear();
        vector<int> v(k);//存儲子圖中每個結點
        unordered_map<int,bool> exist;//是否存在
        for(int i=0;i<k;i++){
            cin>>v[i];
            exist[v[i]]= true;
        }
        //核心,遍歷每條邊,若子圖中存在該邊,則兩端的結點的度都加1
        for(auto it:edge){
            if(exist[it.first]&&exist[it.second]){
                degree[it.first]++;
                degree[it.second]++;
            }
        }
        sort(v.begin(),v.end(),cmp);
        printf("%d %d %d\n",v[0],v[1],v[2]);
    }

    return 0;
}

還是太菜了我,且學且進步吧。

參考資料

浙江大學計算機與軟件學院2019年保研上機模擬練習7-4 Index of Popularity (30分)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM