笛卡尔树

匿名 (未验证) 提交于 2019-12-03 00:21:02

笛卡尔树是一种特殊的二叉树,其结点包含两个关键字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++)17GJ54
测试点提示结果耗时内存
0sample 1答案正确128KB
1sample 2答案正确128KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确128KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确128KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确128KB
5答案正确128KB
6答案正确128KB


其中在找根节点的时候利用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)17GJ54
测试点提示结果耗时内存
0sample 1答案正确128KB
1sample 2答案正确128KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确128KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确128KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确128KB
5答案正确128KB
6答案正确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答案正确207-4C++ (g++)17GJ54
测试点提示结果耗时内存
0sample 1答案正确128KB
1sample 2答案正确128KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确128KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确128KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确128KB
5答案正确128KB
6答案正确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答案正确207-4C++ (g++)17GJ54
测试点提示结果耗时内存
0sample 1答案正确240KB
1sample 2答案正确236KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确236KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确236KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确240KB
5答案正确236KB
6答案正确240KB

样例输入与输出:

序号输入输出
1
YES 
2
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
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++)17GJ54
测试点提示结果耗时内存
0sample 1答案正确240KB
1sample 2答案正确240KB
2K1满足二叉搜索树,但K2不满足最小堆顺序答案正确240KB
3K2满足最小堆顺序,但K1不满足二叉搜索树答案正确240KB
4K2满足最小堆顺序;K1的每个子树都满足二叉搜索树条件,但整棵树不满足二叉搜索树条件答案正确312KB
5答案正确240KB
6答案正确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;   }  
文章来源: 笛卡尔树
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!