1. 程式人生 > >NYOJ 63-小猴子下落(二叉樹)

NYOJ 63-小猴子下落(二叉樹)

63-小猴子下落

題目描述

有一顆二叉樹,最大深度為D,且所有葉子的深度都相同。所有結點從左到右從上到下的編號為1,2,3,·····,2的D次方減1。在結點1處放一個小猴子,它會往下跑。每個內結點上都有一個開關,初始全部關閉,當每次有小猴子跑到一個開關上時,它的狀態都會改變,當到達一個內結點時,如果開關關閉,小猴子往左走,否則往右走,直到走到葉子結點。

一些小猴子從結點1處開始往下跑,最後一個小猴兒會跑到哪裡呢?

輸入描述

輸入二叉樹葉子的深度D,和小猴子數目I,假設I不超過整棵樹的葉子個數,D<=20.最終以 0 0 結尾

輸出描述

輸出第I個小猴子所在的葉子編號。

樣例輸入

4 2
3 4
0 0

樣例輸出

12
7

思路1

  • 深度為D的滿二叉樹,結點數為2^D-1;
  • 如果把結點從上到下從左到右編號為1,2,3…,則結點k的左右子結點編號分別為2k,2k+1。
  • 記開關關閉為0,開啟為1

程式碼

#include<iostream>
#include<cstdio>
using namespace std;
const int maxd=20;
int s[1<<maxd]; //最大結點個數為2^maxd-1
int main()
{
    int D,I;
    while
((cin>>D>>I)&&(D!=0&&I!=0)) { memset(s,0,sizeof(s)); int k,n=(1<<D)-1; for(int i=0;i<I;i++) { k=1; while(k<=n) //k>n時,越界 { s[k] = !s[k]; k=s[k]?2*k:2*k+1; }
} cout<<k/2<<endl; } return 0; }

思路2

每隻猴子都會落在根結點上,因此前兩隻猴子必然是一個在左子樹,一個在右子樹,對於那些落入根結點左子樹的猴子來說,只需要知道該猴子是第幾只落在根的左子樹裡,就可以知道它下一步往左還是往右走。
如果使用題目中給出的編號I,則當I是奇數時,它是往左走的第(I+1)/2個小球;當I是偶數時,它是往右走的第I/2個小球。

程式碼

#include<stdio.h>
int main()
{
    int D,I;
    while(scanf("%d%d",&D,&I)==2)
    {
        if(D==0&&I==0) break;
        int k=1;
        for(int i=0;i<D-1;i++)
        {
            if(I%2)
            {
                k=k*2;I=(I+1)/2;
            }
            else
            {
                k=k*2+1;I=I/2;
            }
        }
        printf("%d\n",k);
    }
    return 0;
}