涉及知识
- 1132 sscanf(),浮点错误
- 1133 链表重排(cmp函数、假装重排= =)
- 1134 图的点覆盖(stl set应用)
- 1135 红黑树,二叉树建树,DFS
1132 Cut Integer (20 分)
喜提新的错误种类——浮点错误
-
查了一下,柳神经验丰富
-
若N = 1200,a = 12, b = 0,直接N%(a✖️b)就会GG……要先判0
而且重读题目发现,cut a K digits lone integer Z into two integers of (K/2) digits long integers A and B。
有位朋友提醒过我,PAT里k-digit的数别用int,用string存更保险,可以避免前导零导致的问题(不知此题有没有这样的卡点)。然后sprintf……以下省略。
另外,pow函数慎用,浮点运算有精度丢失,可以先乘1.0变double
#include
#include
#include
#include
typedef long long LL;
using namespace std;
int main() {
int nn;
LL num;
string str;
cin >> nn;
for (int i = 0; i < nn; ++i) {
cin >> str;
sscanf(str.data(), "%lld", &num);
int len = str.length();
int exp = pow(10, len / 2);
LL aa = num / exp, bb = num % exp;
bool res = false;
if (aa * bb == 0) {
printf("No\n");
continue;
}
if (num % (aa * bb) == 0)
res = true;
puts(res ? "Yes" : "No");
}
return 0;
}
1133 Splitting A Linked List (25 分)
链表重排,静态链表假装重排的套路。
Node中需要addr和order用来串起来然后假装重排,cmp规则是分类(node中的kind)然后同一类的仍保持原顺序。(⚠️分类要在串成一条链时再做,而不是输入时,这个node可能根本不在链上!!!)
#include
#include
#define INF 0x3fffffff
using namespace std;
int head, nn, kk;
struct Node {
int addr, next, order, kind = INF, key;
} list[100000];
bool cmp(const Node &n1, const Node &n2) {
if (n1.kind != n2.kind) return n1.kind < n2.kind;
return n1.order < n2.order;
}
int main() {
scanf("%d%d%d", &head, &nn, &kk); // if(nn==6 && kk== 66) while (1); kind
for (int i = 0; i < nn; ++i) {
int addr, key, next;
scanf("%d%d%d", &addr, &key, &next);
list[addr] = Node{addr, next, INF, 3, key};
}
int curr = head, order = 0;
while (curr != -1) {
int key = list[curr].key, kind;
if (key < 0) kind = 0;
else if (key <= kk) kind = 1;
else kind = 2;
list[curr].order = ++order;
list[curr].kind = kind;
curr = list[curr].next;
}
if (order == 0) {
puts("-1");
return 0;
}
sort(list, list + 100000, cmp);
for (int i = 0; i < order; ++i) {
printf("%05d %d ", list[i].addr, list[i].key);
(i + 1 < order) ? printf("%05d\n", list[i + 1].addr) : puts("-1");
}
return 0;
}
1134 Vertex Cover (25 分)
- 法1:遍历边集,确定是不是边集中所有边都至少有一个结点在所给点集中。set find……、
- 法2:降维上瘾了……图用邻接表存储。另外存边集,一条边直接高四位v1低四位v2,一个int表示了,统统放到set
edges里。
然后,给出点集时,造一个临时的边集,判断是不是 == edges……
#include
#include
#include
#include
using namespace std;
set edges;
vector graph[10001];
int main() {
int nn, mm;
scanf("%d%d", &nn, &mm);
for (int i = 0; i < mm; ++i) {
int a, b;
scanf("%d%d", &a, &b);
edges.insert(min(a, b) * 10000 + max(a, b));
graph[a].emplace_back(b);
graph[b].emplace_back(a);
}
int nq;
scanf("%d", &nq);
for (int j = 0; j < nq; ++j) {
int num;
set temp;
scanf("%d", &num);
for (int i = 0; i < num; ++i) {
int v1;
scanf("%d", &v1);
for (auto v2:graph[v1]) {
temp.insert(min(v1, v2) * 10000 + max(v1, v2));
}
}
puts(temp == edges ? "Yes" : "No");
}
return 0;
}
1135 Is It A Red-Black Tree (30 分)
红黑树与AVL树
There is a kind of balanced binary search tree named red-black tree in the data structure. It has the following 5 properties:
(1) Every node is either red or black.
(2) The root is black. (直接看先序第一个的颜色判断就好哈)
(3) Every leaf (NULL) is black.
(4) If a node is red, then both its children are black.
(5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.
红黑树不是AVL树,不要求左子树右子树高度差不超过1。红黑树和AVL树都属于自平衡二叉搜索树。
-
柳神的题解
先按照先序和大小关系建树(非递归),再分别用2个递归函数去check条件4、5
-
我的方法
- 按照中序(排好序的序列就是二叉查找树的中序呀)、先序递归建树,在建树时做条件4的判断。
- 判断根是否是黑色,从根部DFS一波判断是否满足条件5。。。(因为已经check过满足条件4,只要确定从root到任意叶子的简单路径经过相同数量的黑色结点就好)
#include
#include
#include
using namespace std;
struct Node {
int color;
Node *lchild = NULL, *rchild = NULL;
};
bool cmp(const int a, const int b) {
return abs(a) < abs(b);
}
int nn, pre_order[31], in_order[31];
bool isRBT;
Node *createTree(int pre_st, int pre_ed, int in_st, int in_ed) {
if (pre_st > pre_ed || in_st > in_ed) return NULL;
if (pre_st == pre_ed && in_st == in_ed) {
int key = pre_order[pre_st], color = 1;
if (key < 0) {
color = -1;
}
return new Node{color, NULL, NULL};
}
int rkey = pre_order[pre_st], pos = -1, lsize;
for (int i = in_st; i <= in_ed; ++i) {
if (in_order[i] == rkey) {
pos = i;
lsize = i - in_st;
}
}
Node *root = new Node;
root->color = rkey < 0 ? -1 : 1;
root->lchild = createTree(pre_st + 1, pre_st + lsize, in_st, pos - 1);
root->rchild = createTree(pre_st + lsize + 1, pre_ed, pos + 1, in_ed);
if (root->color == -1 &&
((root->lchild && root->lchild->color != 1)
|| (root->rchild && root->rchild->color != 1)))
isRBT = false;
return root;
}
int curr_cnt = 0;
void DFS(Node *root, int cnt) {
if (root == NULL) {
if (curr_cnt == 0) curr_cnt = cnt;
else if (curr_cnt != cnt) isRBT = false;
return;
}
int extra = (root->color == 1) ? 1 : 0;
DFS(root->lchild, cnt + extra);
DFS(root->rchild, cnt + extra);
}
int main() {
int test;
scanf("%d", &test);
for (int i = 0; i < test; ++i) {
scanf("%d", &nn);
for (int j = 0; j < nn; ++j) {
scanf("%d", &pre_order[j]);
in_order[j] = pre_order[j];
}
isRBT = true;
sort(in_order, in_order + nn, cmp);
Node *root = createTree(0, nn - 1, 0, nn - 1);
if (isRBT && root->color == -1) isRBT = false;
if (isRBT) {
curr_cnt = 0;
DFS(root, 0);
}
puts(isRBT ? "Yes" : "No");
}
return 0;
}