时间限制: 400 ms 内存限制: 64 MB 代码长度限制: 16 KB |
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.
For example, the tree in Figure 1 is a red-black tree, while the ones in Figure 2 and 3 are not.
Figure 1 | Figure 2 | Figure 3 |
For each given binary search tree, you are supposed to tell if it is a legal red-black tree.
Input Specification:
Each input file contains several test cases. The first line gives a positive integer K (≤30) 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 tree. The second line gives the preorder traversal sequence of the tree. While all the keys in a tree are positive integers, we use negative signs to represent red nodes. All the numbers in a line are separated by a space. The sample input cases correspond to the trees shown in Figure 1, 2 and 3.
Output Specification:
For each test case, print in a line "Yes" if the given tree is a red-black tree, or "No" if not.
Sample Input:
3
9
7 -2 1 5 -4 -11 8 14 -15
9
11 -2 1 -7 5 -4 8 14 -15
8
10 -7 5 -6 8 15 -11 17
Sample Output:
Yes
No
No
因为自己非科班,完全没学过红黑树,刚看标题的时候以为大佬们都很熟悉红黑树了,就先过了一遍算法导论13章红黑树,看完觉得也就那么回事,除了删除操作太长懒得看以外,5条性质还是很好掌握的。回头来看题,5条性质都给了,也没有插入删除操作,就是纯考性质,难度比A1123差远了,不要被那30分给懵逼了。
性质(《算法导论》):
1、每个结点或是 红色的,或是黑色的;
2、根结点是黑色的;
3、每个叶结点(NIL)是黑色的;
4、如果一个结点是红色的,则它的两个子结点都是黑色的;
5、对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。
题意:因为最多30组,每组30个,又给了先序,那就别客气,直接静态链表存储、递归建树。然后考察性质:因为最多30个结点,递归考虑每个结点,性质①不需考虑;性质②可以直接判断RBT[ROOT].color;性质③也没考到,不过说的比较含糊,这里的叶结点是指在真正的叶结点下面假想的两个NIL结点,主要为插入删除操作服务的,而真正的叶结点是红是黑都可以,这就解释了图①,不明白可以看一下《算法导论》;性质④判断当前为红色时,两个孩子是否为黑;性质⑤可以用归纳法证明红黑树的两个子树也是红黑树,只需递归的判断两子树黑高(简单路径上黑色结点的个数,不算自己)是否相等;
#define Abs(a) (((a)<0)?(0-(a)):(a))
#define RED 0
#define BLACK 1
#define NOTRBTREE -2
#define NULLPTR -1
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=35;
int K,N,cnt,ROOT;
struct node{
int key,color,left,right;
}RBT[MAXN];
int NewNode(int key){
RBT[cnt].color=key<0?RED:BLACK;
RBT[cnt].key=Abs(key);
RBT[cnt].left=RBT[cnt].right=NULLPTR;
return cnt++;
}
void Insert(int key,int &root){
if(root==NULLPTR)
root=NewNode(key);
else if( Abs(key) < RBT[root].key )
Insert(key,RBT[root].left);
else
Insert(key,RBT[root].right);
}
int isRBT(int root){
if(RBT[ROOT].color==RED) return NOTRBTREE; //根结点,性质2;
if(root==NULLPTR) return 0; //https://blog.csdn.net/iserfj/article/details/82121467
if(RBT[root].color==RED){ //红色结点的孩子必为黑色,性质4;
if(RBT[root].left !=NULLPTR && RBT[RBT[root].left ].color==RED) return NOTRBTREE;
if(RBT[root].right!=NULLPTR && RBT[RBT[root].right].color==RED) return NOTRBTREE;
}
int LCB=isRBT(RBT[root].left),RCB=isRBT(RBT[root].right); /* 某结点到其任意叶结点的简单路径上黑色结点的 */
if(LCB==NOTRBTREE || RCB==NOTRBTREE) return NOTRBTREE; /* 个数相等,可递归的判断其左右孩子到其叶结点 */
return LCB==RCB?LCB+(RBT[root].color==BLACK?1:0):NOTRBTREE; /* 的简单路径上黑色结点的个数是否相等,性质5; */
}
int main()
{
int key;
scanf("%d",&K);
for(int i=0;i<K;++i){
cnt=0;
ROOT=NULLPTR;
scanf("%d",&N);
for(int j=0;j<N;++j){
scanf("%d",&key);
Insert(key,ROOT);
}
printf("%s\n",isRBT(ROOT)!=NOTRBTREE?"Yes":"No");
}
return 0;
}