Codeforces Round #287 (Div. 2) C. Guess Your Way Out!+二叉树

C. Guess Your Way Out!
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Amr bought a new video game "Guess Your Way Out!". The goal of the game is to find an exit from the maze that looks like a perfect binary tree of height h. The player is initially standing at the root of the tree and the exit from the tree is located at some leaf node.

Let's index all the leaf nodes from the left to the right from 1 to 2h. The exit is located at some node n where 1 ≤ n ≤ 2h, the player doesn't know where the exit is so he has to guess his way out!

Amr follows simple algorithm to choose the path. Let's consider infinite command string "LRLRLRLRL..." (consisting of alternating characters 'L' and 'R'). Amr sequentially executes the characters of the string using following rules:

  • Character 'L' means "go to the left child of the current node";
  • Character 'R' means "go to the right child of the current node";
  • If the destination node is already visited, Amr skips current command, otherwise he moves to the destination node;
  • If Amr skipped two consecutive commands, he goes back to the parent of the current node before executing next command;
  • If he reached a leaf node that is not the exit, he returns to the parent of the current node;
  • If he reaches an exit, the game is finished.

Now Amr wonders, if he follows this algorithm, how many nodes he is going to visit before reaching the exit?

Input

Input consists of two integers h, n (1 ≤ h ≤ 501 ≤ n ≤ 2h).

Output

Output a single integer representing the number of nodes (excluding the exit node) Amr is going to visit before reaching the exit by following this algorithm.

Sample test(s)
input
1 2
output
2
input
2 3
output
5
input
3 6
output
10
input
10 1024
output
2046



解决方案:此题主要考察完全二叉树,暴力是不可以的,但根据它的特性,我们搜索的时候可以减掉大部分的枝叶。

         我们先按照题目的算法走下去,到达叶子节点,然后若该节点不是出口,则求出这个叶子和出口的最近公共祖先,在祖先节点直接跑另一边搜索,这边已经没有必要在搜索下去了,可以直接计算实际中要走的点数,这样直到走到出口位置。

         然后就是如何计算点数的问题了,我们从根节点开始,假如入公共祖先的层编号是llevel,他的儿子的层数为level,节点个数为 d1=2^0+...+2^(level-1),再加上该祖先以上没有算入的节点d2=h-llevel-level,节点个数为d1+d2;然后进入以该公共祖先开始的子问题更新llevel和level,累加节点个数。最后到了出口时,还要记得统计从走过的没有计入的点数d3=h-llevel。

code:

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int h;
long long n;
long long dfs(long long node,int dir,int level)
{

    if(level==h) return node;
    if(dir==0)
    {
        dfs(node*2,!dir,level+1);
    }
    else
    {
        dfs(node*2+1,!dir,level+1);
    }
}///模拟题目算法的走的过程,一直到叶子
long long lac(long long son,long long exit,int *level)
{
    long long p1=son;
    long long p2=exit;
    int l=0;
    while(p1!=p2)
    {
        l++;
        p1/=2LL;
        p2/=2LL;

    }
    *level=l;
    return p1;
}///求两个节点的公共祖先,并得出以该公共祖先为根的子树的层数
int main()
{
    while(~scanf("%d%I64d",&h,&n))
    {
        long long sum=0;
        long long exit=((1LL<<h)+(n-1));///把叶子节点编号转为二叉树中的节点值
        long long node=dfs(1,0,0);
        int dir,level=0,llevel=0;
        while(node!=exit)
        {
            if(node<exit) dir=1;
            else dir=0;
            long long pa=lac(node,exit,&level);
            for(int i=0; i<(level); i++)
            {
                sum+=(1LL<<i);
            }
            sum+=(h-llevel-level);///h-llevel是以当前的子树的层数
            llevel=h-level;///下一子树的层编号
            node=dfs(pa,dir,llevel);///搜索下一子树
        }
        sum+=h-llevel;///从当前子树搜索下来到达了出口,计算该路径经过的所有节点数
        printf("%I64d\n",sum);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值