All for PAT秋考 | 1116 - 1123

涉及知识

  • 1118 并查集(模板题)
  • 1119 二叉树建树(前序、后序,唯一否?)
  • 1121 set应用,复杂度
  • 1123 AVL tree + 判断完全二叉树

1116 - 1119

1116 Come on! Let's C (20 分)

水题

#include <cstdio>
#include <cmath>

#define INF 0x3ffffff
using namespace std;
struct Candidate {
    int id, rank = -1;
    bool checked = false;
} candidates[10001];

int getAward(int mid) {
    int rank = candidates[mid].rank;
    if (rank == -1) return -1;
    if (!candidates[mid].checked) candidates[mid].checked = true;
    else return 0;
    if (rank == 1) return 1;
    int bound = sqrt(rank);
    for (int i = 2; i <= bound; ++i) {
        if (rank % i == 0) return 3;
    }
    return 2;
}

int main() {
    int nn;
    scanf("%d", &nn);
    int id;
    for (int i = 1; i <= nn; ++i) {
        scanf("%d", &id);
        candidates[id].id = id, candidates[id].rank = i;
    }
    int kk;
    scanf("%d", &kk);
    for (int j = 0; j < kk; ++j) {
        scanf("%d", &id);
        printf("%04d: ", id);
        switch (getAward(id)) {
            case 1: // rank 1
                puts("Mystery Award");
                break;
            case 2: // rank prime
                puts("Minion");
                break;
            case 3: // other rank
                puts("Chocolate");
                break;
            case -1: //not exist
                puts("Are you kidding?");
                break;
            case 0:
                puts("Checked");
                break;
        }
    }
    return 0;
}

1117 Eddington Number (25 分)

"Eddington number", E -- that is, the maximum integer E such that it is for E days that one rides more than E miles. Eddington's own E was 87.Now given everyday's distances that one rides for N days, you are supposed to find the corresponding E (≤N).

  • ⚠️题意理解:找出N个数中,存在E个大于E的数。求最大的E。
  • 直接遍历复杂度到n^2,所以想到排序。
  • 从大到小排序,从头遍历直到当前元素不再大于已遍历过的元素个数。
#include <cstdio>
#include <algorithm>
#include <functional>

using namespace std;
int nn, recs[100001]; // from 1 to nn;
int main() {
    scanf("%d", &nn);
    for (int i = 0; i < nn; ++i) {
        scanf("%d", &recs[i]);
    }
    sort(recs, recs + nn, greater<>());
    int mmax = 0;
    while (mmax < nn && recs[mmax] > mmax + 1)
        mmax++;
    printf("%d\n", mmax);
    return 0;
}

1118 Birds in Forest (25 分)

并查集模板题

#include <cstdio>
#include <algorithm>

using namespace std;

int uf[10001];

int _find(int ii) {
    return uf[ii] < 0 ? ii : uf[ii] = _find(uf[ii]);
}

void _union(int a, int b) {
    a = _find(a);
    b = _find(b);
    if (a != b) {
        uf[a] += uf[b];
        uf[b] = a;
    }
}

int main() {
    int n_bird = -1, n_tree = 0, nn;
    fill(uf, uf + 10001, -1);
    scanf("%d", &nn);
    for (int i = 0; i < nn; ++i) {
        int cnt;
        scanf("%d", &cnt);
        if (cnt) {
            int head, temp;
            scanf("%d", &head);
            n_bird = max(n_bird, head);
            for (int j = 1; j < cnt; ++j) {
                scanf("%d", &temp);
                n_bird = max(n_bird, temp);
                _union(head, temp);
            }
        }
    }
    for (int i = 1; i <= n_bird; ++i) {
        _find(i);
        if (uf[i] < 0) n_tree++;
    }
    int nq;
    scanf("%d", &nq);
    printf("%d %d\n", n_tree, n_bird);
    int b1, b2;
    for (int i = 0; i < nq; ++i) {
        scanf("%d%d", &b1, &b2);
        puts(_find(b1) == _find(b2) ? "Yes" : "No");
    }
    return 0;
}

1119 Pre- and Post-order Traversals (30 分)

⚠️急着上手,没有冷静分析。这递归写的,略难受。下面来分析一波——

  • 以下分析前提是树中的结点key值不重复
  1. 为什么前序、后序序列,可能不能唯一确定一棵二叉树
    • 前序: 左子树 右子树
      后序:左子树 右子树
      中序:左子树 右子树

    • 唯一确定一棵树的形态,关键在于找到根结点,并且划分开左右子树。前序、后序中任一个可以用来确定根结点,但只有中序才能根据根结点key值,找到根结点位置,划分开左右子树。
  2. 什么情况下给定前序、后序序列,二叉树形态不唯一
    • 前序:根 |左根 左 左…… | 右根 右 右……
      后序:左 左…… 左根 | 右 右…… 右根 | 根

    • 前序中,根右边挨着的X一定是子树的根,可能是左子树的根或者右子树的根。
      后序中,根左边挨着的Y一定是子树的根,可能是左子树的根或者右子树的根。

      • 若X == Y,则根只有左子树/只有右子树。但不知道究竟是左子树还是右子树。
      • 若X != Y,则X == 左根,Y == 右根,这一步左右子树的划分是唯一的。

  • 本题要求:不唯一时,随意输出一种可能的二叉树。不妨,不唯一的划分统统划给左子树。
    下面是当时的代码。。。太过走弯路= =
#include <cstdio>
#include <algorithm>
#include <set>

using namespace std;
struct Node {
    int key;
    Node *lchild = NULL, *rchild = NULL;
};
int pre_order[31], post_order[31], nn_node, cnt = 0;
bool _unique = true;

Node *createBTree(int pre_st, int pre_ed, int post_st, int post_ed) {
    if (pre_st > pre_ed || post_st > post_ed) return NULL;
    Node *root = new Node;
    int rkey = pre_order[pre_st]; //pre_order[pre_st] = post_order[post_ed]
    root->key = rkey;
    int ltree_size = 0, bound = pre_ed - pre_st; //bound = ltree_size + rtree_size
    if (bound == 0)
        return root;
    set<int> pre_lkeys, post_lkeys;
    int lroot_pre, lroot_post, rroot_pre, rroot_post;
    int curr_type = 0, one_possible_lsize;

    // rtree == NULL
    lroot_pre = pre_order[pre_st + 1];
    lroot_post = post_order[post_ed - 1];
    if (lroot_pre == lroot_post) {
        one_possible_lsize = bound;
        curr_type++;
    }

    // ltree == NULL
    rroot_pre = pre_order[pre_st + 1];
    rroot_post = post_order[post_ed - 1];
    if (rroot_pre == rroot_post) {
        one_possible_lsize = 0;
        curr_type++;
    }

    //both not NULL
    if (curr_type < 2) {
        for (ltree_size = 1; ltree_size < bound; ++ltree_size) {
            pre_lkeys.insert(pre_order[pre_st + ltree_size]);
            post_lkeys.insert(post_order[post_st + ltree_size - 1]);
            if (pre_lkeys == post_lkeys) {
                lroot_pre = pre_order[pre_st + 1];
                lroot_post = post_order[post_st + ltree_size - 1];
                rroot_pre = pre_order[pre_st + ltree_size + 1];
                rroot_post = post_order[post_ed - 1];
                if (lroot_pre == lroot_post && rroot_pre == rroot_post) {
                    curr_type++;
                    one_possible_lsize = ltree_size;
                }
            }
            if (curr_type > 1) break;
        }
    }
    if (curr_type > 1) _unique = false;
    root->lchild = createBTree(pre_st + 1, pre_st + one_possible_lsize, post_st, post_st + one_possible_lsize - 1);
    root->rchild = createBTree(pre_st + one_possible_lsize + 1, pre_ed, post_st + one_possible_lsize, post_ed - 1);
    return root;
}

void in_order_traverse(Node *root) {
    if (root == NULL) return;
    in_order_traverse(root->lchild);
    printf("%d", root->key);
    cnt++;
    printf(cnt < nn_node ? " " : "\n");
    in_order_traverse(root->rchild);
}

int main() {
    scanf("%d", &nn_node);
    for (int i = 0; i < nn_node; ++i) {
        scanf("%d", &pre_order[i]);
    }
    for (int i = 0; i < nn_node; ++i) {
        scanf("%d", &post_order[i]);
    }
    Node *root = createBTree(0, nn_node - 1, 0, nn_node - 1);
    puts(_unique ? "Yes" : "No");
    in_order_traverse(root);
    return 0;
}

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

1120 - 1123

1120 Friend Numbers (20 分)

水题

#include <cstdio>
#include <set>

using namespace std;

int main() {
    int nn, temp;
    set<int> res;
    scanf("%d", &nn);
    for (int i = 0; i < nn; ++i) {
        scanf("%d", &temp);
        res.insert(temp / 10000 + temp / 1000 % 10 + temp / 100 % 10 + temp / 10 % 10 + temp % 10);
    }
    int size = res.size();
    printf("%d\n", size);
    for (auto &item:res) {
        printf("%d", item);
        printf(--size ? " " : "\n");
    }
    return 0;
}

1121 Damn Single (25 分)

set基本应用,myset.find(要查找的元素) != myset.end()

再次强调set不可sort重排序!!!定义set之后就不能再改排序规则了。
set、map的实现都是基于 红黑树(一种平衡二叉树),插入、查找、删除复杂度均近似O(log n)。这里set的删除指的是erase(元素),erase(迭代器)为常数复杂度,还有一种iterator erase (const_iterator first, const_iterator last)。
来自lcpl96@cnblogs
#include <cstdio>
#include <set>
#include <cstring>

using namespace std;
int cp_map[100001];

int main() {
    memset(cp_map, -1, sizeof(cp_map));
    int ncp, nab;
    scanf("%d", &ncp);
    int t1, t2;
    for (int i = 0; i < ncp; ++i) {
        scanf("%d%d", &t1, &t2);
        cp_map[t1] = t2;
        cp_map[t2] = t1;
    }
    set<int> res, temp_single;
    scanf("%d", &nab);
    for (int i = 0; i < nab; ++i) {
        scanf("%d", &t1);
        if (cp_map[t1] == -1)
            res.insert(t1);
        else temp_single.insert(t1);
    }
    for (auto item:temp_single) {
        if (temp_single.find(cp_map[item]) == temp_single.end()) {
            res.insert(item);
        }
    }
    int size = res.size();
    printf("%d\n", size);
    for (auto item: res) {
        printf("%05d", item);
        printf(--size ? " " : "\n");
    }
    return 0;
}

1122 Hamiltonian Cycle (25 分)

按照题中给的定义,判断即可。

#include <cstdio>

using namespace std;
int nn, mm;
bool graph[201][201] = {false};

int main() {
    scanf("%d%d", &nn, &mm);
    int v1, v2;
    for (int i = 0; i < mm; ++i) {
        scanf("%d%d", &v1, &v2);
        graph[v1][v2] = graph[v2][v1] = true;
    }
    int nq;
    scanf("%d", &nq);
    for (int i = 0; i < nq; ++i) {
        bool res = true;
        int len;
        scanf("%d", &len);
        if (len != nn + 1) res = false;
        bool visited[201] = {false};
        int src, pre, curr;
        scanf("%d", &src);
        pre = src;
        for (int j = 1; j < len; ++j) {
            scanf("%d", &curr);
            if (res) {
                if (!graph[pre][curr]) {
                    res = false;
                } else {
                    if (!visited[curr])
                        visited[curr] = true;
                    else res = false;
                }
            }
            pre = curr;
        }
        if (src != pre) res = false;
        puts(res ? "YES" : "NO");
    }
    return 0;
}

1123 Is It a Complete AVL Tree (30 分)

  • ⚠️Node *root = NULL; 所有指针必须初始化
  • 插入后,调整中,都要及时updateHeight(),并且调整中要从子到父update
  • getHeight()、updateHeight()、getBalancingFactor(),左旋、右旋。写法见AVL tree
#include <cstdio>
#include <algorithm>
#include <queue>

using namespace std;
struct Node {
    int key, height;
    Node *lchild = NULL, *rchild = NULL;
};

bool isCBT = true, isLeaf = false;
int nn;

int getHeight(Node *root) {
    return (root == NULL) ? 0 : root->height;
}

void updateHeight(Node *root) {
    root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
}

int getBalancingFactor(Node *root) {
    return getHeight(root->lchild) - getHeight(root->rchild);
}

void LeftRotate(Node *&root) {
    Node *temp = root->rchild;
    root->rchild = temp->lchild;
    temp->lchild = root;
    updateHeight(root);
    updateHeight(temp);
    root = temp;
}

void RightRotate(Node *&root) {
    Node *temp = root->lchild;
    root->lchild = temp->rchild;
    temp->rchild = root;
    updateHeight(root);
    updateHeight(temp);
    root = temp;
}


void insertNode(Node *&root, int x) {
    if (root == NULL) {
        root = new Node;
        root->key = x;
        root->height = 1; //注意!!!root = new Node{value, 1, NULL, NULL};
        return;
    }
    if (x < root->key) {
        insertNode(root->lchild, x);
        updateHeight(root);
        if (getBalancingFactor(root) == 2) {
            if (getBalancingFactor(root->lchild) == 1) { // LL
                RightRotate(root);
            } else { // LR
                LeftRotate(root->lchild); // after: LL
                RightRotate(root);
            }
        }
    } else {
        insertNode(root->rchild, x);
        updateHeight(root);
        if (getBalancingFactor(root) == -2) {
            if (getBalancingFactor(root->rchild) == -1) { // RR
                LeftRotate(root);
            } else { // RL
                RightRotate(root->rchild); // after: RR
                LeftRotate(root);
            }
        }
    }
}

void levelOrder_CheckCBT(Node *root) {
    queue<Node *> mq;
    mq.push(root);
    while (!mq.empty()) {
        Node *curr = mq.front();
        mq.pop();
        if (isLeaf && (curr->lchild || curr->rchild))
            isCBT = false;
        if (!isLeaf && isCBT && !(curr->lchild && curr->rchild))
            isLeaf = true;
        if (isCBT && curr->rchild && !curr->lchild)
            isCBT = false;
        printf("%d", curr->key);
        printf((--nn) ? " " : "\n");
        if (curr->lchild) mq.push(curr->lchild);
        if (curr->rchild) mq.push(curr->rchild);
    }
}

int main() {
    int temp;
    scanf("%d", &nn);
    Node *root = NULL; //必须!!!!! 初始化为NULL
    for (int i = 0; i < nn; ++i) {
        scanf("%d", &temp);
        insertNode(root, temp);
    }
    levelOrder_CheckCBT(root);
    puts(isCBT ? "YES" : "NO");
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容