7-4 笛卡尔树(20 分)
笛卡尔树是一种特殊的二叉树,其结点包含两个关键字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
提交结果
提交时间 | 状态 | 分数 | 题目 | 编译器 | 耗时 | 用户 |
---|---|---|---|---|---|---|
2018/5/24 21:25:05 | 答案正确 | 20 | 7-4 | C++ (g++) | 2 ms | 17GJ54 |
测试点 | 提示 | 结果 | 耗时 | 内存 |
---|---|---|---|---|
0 | sample 1 | 答案正确 | 2 ms | 128KB |
1 | sample 2 | 答案正确 | 1 ms | 128KB |
2 | K1满足二叉搜索树,但K2不满足最小堆顺序 | 答案正确 | 2 ms | 128KB |
3 | K2满足最小堆顺序,但K1不满足二叉搜索树 | 答案正确 | 2 ms | 128KB |
4 | K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件 | 答案正确 | 2 ms | 128KB |
5 | 答案正确 | 2 ms | 128KB | |
6 | 答案正确 | 2 ms | 128KB |
题意:这个题只要分开判断这个树的k1是否符合二叉排序树,k2是否符合最小堆即可。最小堆的判断就是从根节点开始,看他的左右孩子的k2是否都比根节点的k2大,如果是则继续递归,否则flag = 0退出循环。
k1的判断更简单,只要中序遍历一遍k1的值,看知否符合从小到大的排序即可。
其中在找根节点的时候利用vis数组,将有父亲节点的孩子标记,则最后那个没有标记(没有父亲的)就是根节点了。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
int left;
int right;
int k1,k2;
} q[1010];
int flag;
int vis[1010];
void puandui(int num)
{
int left,right;
if(q[num].left!=-1)
{
left = q[num].left;
if(q[left].k2<q[num].k2)//如果左孩子的K2比父亲的K2小则不符合最小堆
{
flag = 0;
return ;
}
puandui(left);//递归
}
if(q[num].right !=-1)
{
right = q[num].right;
if(q[right].k2<q[num].k2)//如果右孩子的K2比父亲的K2小则不符合最小堆
{
flag = 0;
return ;
}
puandui(right);
}
}
int zhongxu1[1010],zhongxu2[1010];
int cnt;
void zhongxu(int num)
{
if(num!=-1)
{
zhongxu(q[num].left);
zhongxu1[cnt] = q[num].k1;
zhongxu2[cnt] = q[num].k1;
cnt++;
zhongxu(q[num].right);
}
}
int main()
{
int n;
scanf("%d",&n);
cnt = 0;
flag = 1;
int l,r,k1,k2;
memset(vis,0,sizeof(vis));
for(int i=0; i<n; i++)
{
scanf("%d %d %d %d",&k1,&k2,&l,&r);
q[i].k1 = k1;
q[i].k2 = k2;
q[i].left = l;
q[i].right = r;
if(l!=-1)//有父亲的左右孩子标记
vis[l] = 1;
if(r!=-1)
vis[r] = 1;
}
int root;
for(int i=0; i<n; i++)
{
if(vis[i]==0)//找根节点
{
root = i;
break;
}
}
puandui(root);//判断k2是否符合最小堆
zhongxu(root);//中序遍历。
sort(zhongxu1,zhongxu1+cnt);//从小到大排序
for(int i=0; i<cnt; i++)
{
if(zhongxu1[i]!=zhongxu2[i])
{
flag = 0;
break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
return 0;}
法2
提交结果
提交时间 | 状态 | 分数 | 题目 | 编译器 | 耗时 | 用户 |
---|---|---|---|---|---|---|
2018/5/24 21:23:41 | 答案正确 | 20 | 7-4 | C (gcc) | 2 ms | 17GJ54 |
测试点 | 提示 | 结果 | 耗时 | 内存 |
---|---|---|---|---|
0 | sample 1 | 答案正确 | 2 ms | 128KB |
1 | sample 2 | 答案正确 | 2 ms | 128KB |
2 | K1满足二叉搜索树,但K2不满足最小堆顺序 | 答案正确 | 2 ms | 128KB |
3 | K2满足最小堆顺序,但K1不满足二叉搜索树 | 答案正确 | 2 ms | 128KB |
4 | K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件 | 答案正确 | 2 ms | 128KB |
5 | 答案正确 | 2 ms | 128KB | |
6 | 答案正确 | 2 ms | 128KB |
无非就是用两种遍历方式分别验证每个结点的K1值和K2值是否分别符合规则。
#include <stdio.h>
#include<stdlib.h>
#define ERRORMin 99999//'这个地方其实是有一定风险,因为题目并没有指出K值的上界'
#define ERRORMax -99999//同上
typedef struct node *Node;
struct node {
int K1;
int Max_K1,Min_K1;
int K2;
int Left;
int Right;
}*Decare;
int n;
int Root();
int DLR(int);//前序,Degree Left Right
int LRD(int);//后序,Left Right Degree
int main() {
scanf("%d",&n);
Decare=(Node)malloc(sizeof(struct node)*n);
for(int i=0; i<n; i++) {
scanf("%d",&Decare[i].K1);
scanf("%d",&Decare[i].K2);
scanf("%d",&Decare[i].Left);
scanf("%d",&Decare[i].Right);
Decare[i].Min_K1=ERRORMin;
Decare[i].Max_K1=ERRORMax;
}
int head=Root();
int Result =DLR(head);
if(Result)Result=LRD(head);
if(Result)printf("YES\n");
else printf("NO\n");
return 0;
}
int Root() {
int*temp=(int*)malloc(sizeof(int)*n);
for(int i=0; i<n; i++) {
temp[i]=0;
}
for(int i=0; i<n; i++) {
temp[Decare[i].Left]=1;
temp[Decare[i].Right]=1;
}
for(int i=0; i<n; i++) {
if(!temp[i])return i;
}
return -1;//没有根节点
}
int DLR(int K) { //K2判定
if(K==-1)return 1;
if(Decare[K].Left!=-1)
if(Decare[Decare[K].Left].K2<Decare[K].K2)return 0;
if(Decare[K].Right!=-1)
if(Decare[Decare[K].Right].K2<Decare[K].K2)return 0;
if( DLR(Decare[K].Left)==0)return 0;
if(DLR(Decare[K].Right)==0)return 0;
return 1;
}
int LRD(int K) {//K1判定,先把Min_K1 Max_K1计算出来在比较
if(K==-1)return 1;
if(LRD(Decare[K].Left)==0)return 0;
if(Decare[K].Left==-1)Decare[K].Min_K1=Decare[K].K1;
else Decare[K].Min_K1=Decare[Decare[K].Left].Min_K1;
if(LRD(Decare[K].Right)==0)return 0;
if(Decare[K].Right==-1)Decare[K].Max_K1=Decare[K].K1;
else Decare[K].Max_K1=Decare[Decare[K].Right].Max_K1;
int temp=K;
if(Decare[temp].Left!=-1)
if(Decare[temp].K1<Decare[Decare[temp].Left].Max_K1)return 0;
if(Decare[temp].Right!=-1)
if(Decare[temp].K1>Decare[Decare[temp].Right].Min_K1)return 0;
return 1;
}
法3
提交结果
提交时间 | 状态 | 分数 | 题目 | 编译器 | 耗时 | 用户 |
---|---|---|---|---|---|---|
2018/5/24 21:27:10 | 答案正确 | 20 | 7-4 | C++ (g++) | 2 ms | 17GJ54 |
测试点 | 提示 | 结果 | 耗时 | 内存 |
---|---|---|---|---|
0 | sample 1 | 答案正确 | 2 ms | 128KB |
1 | sample 2 | 答案正确 | 2 ms | 128KB |
2 | K1满足二叉搜索树,但K2不满足最小堆顺序 | 答案正确 | 2 ms | 128KB |
3 | K2满足最小堆顺序,但K1不满足二叉搜索树 | 答案正确 | 2 ms | 128KB |
4 | K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件 | 答案正确 | 2 ms | 128KB |
5 | 答案正确 | 2 ms | 128KB | |
6 | 答案正确 | 2 ms | 128KB |
BST的满足键值判断,要依据中序遍历是否有序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int pre[1010];
struct BST{
int left;
int right;
int k1;
int k2;
}q[1010];
int flag;
void Judge(int num)
{
int left,right;
if(!flag)
return;
if(q[num].left!=-1)
{
left=q[num].left;
if(q[left].k2<q[num].k2)
{
flag=0;
return;
}
Judge(left);
}
if(q[num].right!=-1)
{
right=q[num].right;
if(q[right].k2<q[num].k2)
{
flag=0;
return;
}
Judge(right);
}
}
int bb[1010],aa[1010];
int num_b;
void inorder(int num)
{
if(num==-1)
return;
inorder(q[num].left);
aa[num_b]=bb[num_b]=q[num].k1;
num_b++;
inorder(q[num].right);
}
int main()
{
int n,k1,k2,left,right;
memset(pre,0,sizeof(pre));
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d%d%d",&k1,&k2,&left,&right);
q[i].k1=k1;
q[i].k2=k2;
q[i].left=left;
q[i].right=right;
if(left!=-1)
pre[left]++;
if(right!=-1)
pre[right]++;
}
int root;
for(int i=0;i<n;i++)
{
if(!pre[i])
{
root=i;
break;
}
}
flag=1;
Judge(root);
num_b=0;
inorder(root);
for(int i=0;i<num_b;i++)
{
for(int j=i+1;j<num_b;j++)
{
if(aa[j]<aa[j-1])
{
int temp=aa[j-1];
aa[j-1]=aa[j];
aa[j]=temp;
}
}
}
for(int i=0;i<num_b;i++)
{
if(aa[i]!=bb[i])
{
flag=0;
break;
}
}
if(flag)
puts("YES");
else
puts("NO");
return 0;
}
法4
提交结果
提交时间 | 状态 | 分数 | 题目 | 编译器 | 耗时 | 用户 |
---|---|---|---|---|---|---|
2018/5/24 21:26:28 | 答案正确 | 20 | 7-4 | C++ (g++) | 3 ms | 17GJ54 |
测试点 | 提示 | 结果 | 耗时 | 内存 |
---|---|---|---|---|
0 | sample 1 | 答案正确 | 2 ms | 240KB |
1 | sample 2 | 答案正确 | 3 ms | 236KB |
2 | K1满足二叉搜索树,但K2不满足最小堆顺序 | 答案正确 | 2 ms | 236KB |
3 | K2满足最小堆顺序,但K1不满足二叉搜索树 | 答案正确 | 2 ms | 236KB |
4 | K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件 | 答案正确 | 2 ms | 240KB |
5 | 答案正确 | 3 ms | 236KB | |
6 | 答案正确 | 2 ms | 240KB |
样例输入与输出:
序号 | 输入 | 输出 |
1 | | |
2 | | |
3 | | |
4 | | |
5 | | |
6 | | |
二叉排序树的中序遍历一定是一个从小到大排序的数组,这题我在判断是否是二叉树的时候分了2步, 先得到中序的数组然后来进行判断。方法有点笨。
另外题目给的测试数据有问题,有几处-1的负号不是同一种类型的。大家注意下,自己改回来
#include <iostream>
#include <deque>
using namespace std;
typedef struct
{
int K1;
int K2;
int lChild;
int rChild;
}BNode;
deque<BNode> de;
deque<int> tde;
bool a[1005] = {false};
int sum = 0;
void PreTraval(BNode root)
{
if(root.lChild != -1)
PreTraval(de[root.lChild]);
tde.push_back(root.K1);
if(root.rChild != -1)
PreTraval(de[root.rChild]);
}
bool IsSDD(BNode root)
{
if(root.lChild == -1 && root.rChild == -1)
return true;
else if(root.lChild == -1 && root.rChild != -1)
{
if(de[root.rChild].K2 > root.K2)
return IsSDD(de[root.rChild]);
else
return false;
}
else if(root.lChild != -1 && root.rChild == -1)
{
if(de[root.lChild].K2 > root.K2)
return IsSDD(de[root.lChild]);
else
return false;
}
else
{
if(root.K2 < de[root.lChild].K2 && root.K2 < de[root.rChild].K2)
return IsSDD(de[root.lChild]) && IsSDD(de[root.rChild]);
else
return false;
}
}
bool IsBST()
{
for(int i = 1; i < tde.size(); ++i)
{
if(tde[i] <= tde[i-1])
return false;
}
return true;
}
int main()
{
int n;
cin>>n;
while(n--)
{
BNode tn;
scanf("%d%d%d%d", &tn.K1, &tn.K2, &tn.lChild, &tn.rChild);
// cin>>tn.K1>>tn.K2>>tn.lChild>>tn.rChild;
if(tn.lChild >= 0)
a[tn.lChild] = true;
if(tn.rChild >= 0)
a[tn.rChild] = true;
de.push_back(tn);
}
int rootIndex = 0;
for(int i = 0; i < de.size(); ++i)
if(!a[i])
{
rootIndex = i;
break;
}
PreTraval(de[rootIndex]);
if(IsBST() && IsSDD(de[rootIndex]))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}
法5
提交结果
提交时间 | 状态 | 分数 | 题目 | 编译器 | 耗时 | 用户 |
---|---|---|---|---|---|---|
2018/5/24 21:28:25 | 答案正确 | 20 | 7-4 | C++ (g++) | 3 ms | 17GJ54 |
测试点 | 提示 | 结果 | 耗时 | 内存 |
---|---|---|---|---|
0 | sample 1 | 答案正确 | 2 ms | 240KB |
1 | sample 2 | 答案正确 | 3 ms | 240KB |
2 | K1满足二叉搜索树,但K2不满足最小堆顺序 | 答案正确 | 3 ms | 240KB |
3 | K2满足最小堆顺序,但K1不满足二叉搜索树 | 答案正确 | 3 ms | 240KB |
4 | K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件 | 答案正确 | 3 ms | 312KB |
5 | 答案正确 | 3 ms | 240KB | |
6 | 答案正确 | 2 ms | 240KB |
笛卡尔树的中序遍历应为一升序的序列!
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1017;
int tag[maxn];
typedef struct
{
int k1;
int k2;
int L;
int R;
}Node;
vector<int>a;
vector<Node>b;
void Mid_order(Node T)//中序遍历
{
if(T.L != -1)
{
Mid_order(b[T.L]);
}
a.push_back(T.k1);
if(T.R != -1)
{
Mid_order(b[T.R]);
}
}
int is_dkr(Node T)
{
if(T.L==-1 && T.R==-1)
return 1;
else if(T.L!=-1 && T.R==-1)
{
if(b[T.L].k2 > T.k2)
return is_dkr(b[T.L]);
else
return 0;
}
else if(T.L==-1 && T.R!=-1)
{
if(b[T.R].k2 > T.k2)
return is_dkr(b[T.R]);
else
return 0;
}
else if(T.L!=-1 && T.R!=-1)
{
if(b[T.L].k2 > T.k2 && b[T.R].k2 > T.k2)
return is_dkr(b[T.L]) && is_dkr(b[T.R]);
else
return 0;
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int i, j;
memset(tag,0,sizeof(tag));
a.clear();
b.clear();
Node c;
for(i = 0; i < n; i++)
{
scanf("%d%d%d%d",&c.k1,&c.k2,&c.L,&c.R);
if(c.L >= 0)
{
tag[c.L] = 1;
}
if(c.R >= 0)
{
tag[c.R] = 1;
}
b.push_back(c);
}
int root_node = 0;
for(i = 0; i < b.size(); i++)
{
if(!tag[i])
{
root_node = i;//根节点
break;
}
}
Mid_order(b[root_node]);
int flag = 0;
for(i = 1; i < a.size(); i++)
{
if(a[i] <= a[i-1])
{
flag = 1;
break;
}
}
if(flag)
{
printf("NO\n");
continue;
}
if(!is_dkr(b[root_node]))
{
printf("NO\n");
}
else
{
printf("YES\n");
}
}
return 0;
}