笛卡尔树

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答案正确207-4C++ (g++)2 ms17GJ54
测试点提示结果耗时内存
0sample 1答案正确2 ms128KB
1sample 2答案正确1 ms128KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确2 ms128KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确2 ms128KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确2 ms128KB
5 答案正确2 ms128KB
6 答案正确2 ms128KB

题意:这个题只要分开判断这个树的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答案正确207-4C (gcc)2 ms17GJ54
测试点提示结果耗时内存
0sample 1答案正确2 ms128KB
1sample 2答案正确2 ms128KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确2 ms128KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确2 ms128KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确2 ms128KB
5 答案正确2 ms128KB
6 答案正确2 ms128KB

无非就是用两种遍历方式分别验证每个结点的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答案正确207-4C++ (g++)2 ms17GJ54
测试点提示结果耗时内存
0sample 1答案正确2 ms128KB
1sample 2答案正确2 ms128KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确2 ms128KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确2 ms128KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确2 ms128KB
5 答案正确2 ms128KB
6 答案正确2 ms128KB

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答案正确207-4C++ (g++)3 ms17GJ54
测试点提示结果耗时内存
0sample 1答案正确2 ms240KB
1sample 2答案正确3 ms236KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确2 ms236KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确2 ms236KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确2 ms240KB
5 答案正确3 ms236KB
6 答案正确2 ms240KB

样例输入与输出:

序号输入输出
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
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
NO
3
7
8 27 5 1
9 40 -1 -1
10 20 0 3
12 22 -1 4
15 21 6 -1
5 35 -1 -1
13 23 -1 -1
NO
4
6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 21 -1 4
11 22 –1 -1
5 35 -1 -1
NO
5
9
11 5 3 -1
15 3 4 7
5 2 6 0
6 8 -1 -1
9 6 -1 8
10 1 2 1
2 4 -1 -1
20 7 -1 -1
12 9 -1 -1
NO
6
1
1 1 -1 -1
YES

 

二叉排序树的中序遍历一定是一个从小到大排序的数组,这题我在判断是否是二叉树的时候分了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答案正确207-4C++ (g++)3 ms17GJ54
测试点提示结果耗时内存
0sample 1答案正确2 ms240KB
1sample 2答案正确3 ms240KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确3 ms240KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确3 ms240KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确3 ms312KB
5 答案正确3 ms240KB
6 答案正确2 ms240KB

笛卡尔树的中序遍历应为一升序的序列!

#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;  
}  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值