1110. Complete Binary Tree (25) -- 完全二叉树相关性质, 求树根两种方法

题目地址

https://www.patest.cn/contests/pat-a-practise/1110

题目描述

Given a tree, you are supposed to tell if it is a complete binary tree.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<=20) which is the total number of nodes in the tree – and hence the nodes are numbered from 0 to N-1. Then N lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a “-” will be put at the position. Any pair of children are separated by a space.

Output Specification:

For each case, print in one line “YES” and the index of the last node if the tree is a complete binary tree, or “NO” and the index of the root if not. There must be exactly one space separating the word and the number.

Sample Input 1:
9
7 8
- -
- -
- -
0 1
2 3
4 5
- -
- -
Sample Output 1:
YES 8

Sample Input 2:
8
- -
4 5
0 6
- -
2 3
- 7
- -
- -
Sample Output 2:
NO 1

思路

完全二叉树 定义与性质

  1. 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

  2. 完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。

  3. 一棵二叉树至多只有最下面的一层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树。


本题我按照第二点来做的,就是得到树根,然后利用队列,给节点编号,编号必须有且只有1-n,否则就不是完全二叉树。

ac1

某个节点的入度为0,表示是根节点

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
#include <sstream> 
using namespace std;

const int INF = 0x7fffffff;
const int N = 22;  

int n;

struct data{
  int no; // 编号
  int left;
  int right;
};

int in_degree[N];
data v[N];
int rootNum;

int main(int argc, char const *argv[])  
{  
   // freopen("in.txt", "r", stdin);  
  while(scanf("%d",&n) != EOF)
  {
    string s1,s2;

    for(int i=0;i<n;i++)
    {
      in_degree[i] = 0;
    }

    for(int i=0;i<n;i++)
    {
      cin >> s1 >> s2;
      if(s1 == "-"){
        v[i].left = -1;
      }else{
        stringstream ss;
        ss << s1;
        ss >> v[i].left;
        in_degree[v[i].left] ++;
      }

      if(s2 == "-"){
        v[i].right = -1;
      }else{
        stringstream ss;
        ss << s2;
        ss >> v[i].right;
        in_degree[v[i].right] ++;
      }
    }

    for(int i=0;i<n;i++)
    {
      if(in_degree[i]== 0)
        rootNum = i;
    }

    v[rootNum].no = 1;
    queue<int> que;
    que.push(rootNum);

    while(!que.empty())
    {
      int fa = que.front();
      que.pop();

      if(v[fa].left != -1)
      {
        int leftNum = v[fa].left;
        v[leftNum].no = v[fa].no * 2;
        que.push(leftNum);
      }

      if(v[fa].right != -1)
      {
        int rightNum = v[fa].right;
        v[rightNum].no = v[fa].no * 2 + 1;
        que.push(rightNum);
      }
    }//

    int lastNode;
    bool flag = true;
    for(int i=0;i<n;i++)
    {
      if(v[i].no > n)
        flag = false;
      if(v[i].no == n)
        lastNode = i;
    }
    if(flag){
      printf("YES %d\n",lastNode);
    }else{
      printf("NO %d\n",rootNum);
    }
  }

    return 0;  
}

ac 2,

并查集判断树根,然后构造出二叉树来

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
#include <sstream>
#include <list>
#include <stack> 
#include <map> 
#include <set> 
#include <iterator> 
#include <unordered_map>

using namespace std;

const int INF = 0x7fffffff;

typedef long long int LL;

const int N = 20 + 5;

int n;

struct data{
  int id;
  int left;
  int right;
};

typedef struct node
{
  int val;
  struct node* left;
  struct node* right;
  node(int _val = -1)
  {
    val = _val;
    left = NULL;
    right = NULL;
  }
}Bnode;

int str2int(string s)
{
  stringstream ss;
  ss << s;
  int t;
  ss >> t;
  return t;
}

data v[N];

int fa[N];
int Find(int x)
{
  if(x == fa[x])
    return x;
  return fa[x] = Find(fa[x]);
}
void Merg(int x,int y)
{
  int xx = Find(x);
  int yy = Find(y);
  fa[yy] = xx;
}


Bnode* Create(int id)
{
  if(id > n)
    return NULL;


  Bnode* rt = new Bnode(id);

  if(v[id].left != -1)
    rt->left = Create(v[id].left);
  else
    rt->left = NULL;

  if(v[id].right != -1)
    rt->right = Create(v[id].right);
  else
    rt->right = NULL;

  return rt;
}

int main()
{
  //freopen("in.txt", "r" , stdin);

  while(scanf("%d", &n) != EOF)
  {
    for(int i=0;i<n;i++)
      fa[i] = i;

    for(int i=0;i<n;i++)
    {
      string s1,s2;
      cin >> s1 >> s2;
      int leftVal,rightVal;

      if(s1 == "-")
        leftVal = -1;
      else
      {
        leftVal = str2int(s1);
        if(Find(i) != Find(leftVal)){
          Merg(i, leftVal);
        }
      }

      if(s2 == "-")
        rightVal = -1;
      else
      {
        rightVal = str2int(s2);
        if(Find(i) != Find(rightVal)){
          Merg(i, rightVal);
        }
      }

      v[i].id = i;
      v[i].left = leftVal;
      v[i].right = rightVal;
    }

    set<int> se;
    for(int i= 0;i<n;i++)
    {
      se.insert(Find(i));
    }
    int rtNum = *se.begin();

    Bnode *root = Create(rtNum);


    queue<Bnode*> que;
    queue<int> queId;
    que.push(root);
    queId.push(1);

    bool flag = true;
    int maxTmp = -1;
    int ans ;

    while(!que.empty())
    {
      Bnode* bt = que.front();
      que.pop();
      int index = queId.front();
      queId.pop();

      if(index > n)
      {
        flag = false;
      }
      if(index > maxTmp)
      {
        maxTmp = index;
        ans = bt->val;
      }

      if(bt->left != NULL)
      {
        que.push(bt->left);
        queId.push( 2 * index);
      }

      if(bt->right != NULL)
      {
        que.push(bt->right);
        queId.push( 2 * index + 1);
      }
    }
    if(flag)
    {
      printf("YES ");
      printf("%d", ans);
    }
    else{
      printf("NO ");
      printf("%d", rtNum);
    }
    printf("\n");
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值