涉及知识
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值不重复。
-
为什么前序、后序序列,可能不能唯一确定一棵二叉树
前序:根 左子树 右子树
后序:左子树 右子树 根
中序:左子树 根 右子树-
唯一确定一棵树的形态,关键在于找到根结点,并且划分开左右子树。前序、后序中任一个可以用来确定根结点,但只有中序才能根据根结点key值,找到根结点位置,划分开左右子树。
-
什么情况下给定前序、后序序列,二叉树形态不唯一
前序:根 |左根 左 左…… | 右根 右 右……
后序:左 左…… 左根 | 右 右…… 右根 | 根-
前序中,根右边挨着的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)。
#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;
}