PTA 笛卡尔树
笛卡尔树 (25 分)
笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2。首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树则大。其次所有结点的K2关键字满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中所有结点的K2值小。给定一棵二叉树,请判断该树是否笛卡尔树。
输入格式:
输入首先给出正整数N(≤1000),为树中结点的个数。随后N行,每行给出一个结点的信息,包括:结点的K1值、K2值、左孩子结点编号、右孩子结点编号。设结点从0~(N-1)顺序编号。若某结点不存在孩子结点,则该位置给出−1。
输出格式:
输出YES
如果该树是一棵笛卡尔树;否则输出NO
。
输入样例1:
6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 21 -1 4
15 22 -1 -1
5 35 -1 -1
输出样例1:
YES
输入样例2:
6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 11 -1 4
15 22 -1 -1
50 35 -1 -1
输出样例2:
NO
笛卡尔树的性质:
1.如果只含key值,不含value值的话,此树就像是一颗二叉搜索树。性质和二叉搜索树的性质是一样的,从左子树到右子树依次变大。而val值的意思正好和key值的意思相反。
2.笛卡尔树的以key值为准,中序遍历出的key值必须是从小到大的(不能相等)。
#include<iostream> #include<cstdio> #include<vector> using namespace std; struct node { int key; int val; int lchild; int rchild; }a[1005]; int vis[1005],flag,ans[1005],cnt=0; void fun(int root) { if(!flag) //减少不必要的递归,节约时间 return ; if(a[root].lchild!=-1) //如果左孩子不为-1,则进行下一步操作 { int left=a[root].lchild; if(a[left].key>=a[root].key) //假如该位置的前一个左孩子大于或者等于该位置的key值 // { //则将flag赋值为flase flag=0; return ; } fun(left); } if(a[root].rchild!=-1) //同上,就是该位置的前一个右孩子小于或者等于该位置的val值 { int right=a[root].rchild; if(a[right].val<=a[root].val) { flag=0; return ; } fun(right); } } void in_order(int root)//中序遍历此树 { if(root!=-1) { in_order(a[root].lchild); ans[cnt++]=a[root].key; in_order(a[root].rchild); } } int main() { int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d%d%d%d",&a[i].key,&a[i].val,&a[i].lchild,&a[i].rchild); if(a[i].lchild!=-1) //记录所有出现的结点,没出现的那个节点就是根节点 vis[a[i].lchild]=1; if(a[i].rchild!=-1) vis[a[i].rchild]=1; } int root=-1; for(int i=0;i<n;i++) //找出根节点 if(!vis[i]) { root=i; break; //记住跳出,减少没有必要的循环 } if(root==-1) //判断此树是否为空树 { printf("YES\n"); return 0; } flag=1; //如果为true则是笛卡尔树,否则不是 fun(root); //递归判断此树 in_order(root); //中序遍历 for(int i=0;i<cnt-1;i++) //判断中序遍历出的key值是否符合二叉搜索树的性质(从小到大) if(ans[i]>=ans[i+1]) { flag=0; break; } if(flag) printf("YES\n"); else printf("NO\n"); return 0; }