小球下落(二叉樹編號)

小球下落

有一顆二叉樹,最大深度爲D,且所有葉子的深度都相同,所有結點從上到下從左到右編號爲1,2,3,…,2 ^ D - 1.在結點1處放一個小球,它會往下落。每個內結點上都有一個開關,初始全部關閉,當每次有小球落到一個開關上時,狀態都會改變。當小球到達一個內結點時,如果該結點上的開關關閉,則往左走,否則往右走,直到走到葉子結點。
在這裏插入圖片描述

一些小球從結點1處一次開始下落,最後一個小球將會落到哪裏?輸入葉子深度D和小球個數I,輸出第I個小球最後所在的葉子編號。假設I不超過整棵樹的葉子個數。D<= 20.輸入最多包含1000組數據。

樣例輸入

4 2
3 4
10 1
2 2
2 128
16 12345

樣例輸出:

12
7
512
3
255
36358

數組模擬的方法:運算量大

#include<iostream>
#include<cstring> 
using namespace std;
const int N = 20;
int s[1 << N];//二進制下,每乘一個2就向左進一位,1左移N就相當於1 x 2 ^ N;這裏存最大結點數 
 
int main() 
{
	int D, I;//葉子深度和小球個數 
	while(~ scanf("%d%d", &D, &I)){
		
		memset(s, 0, sizeof(s));//開關初始爲關閉 
		
		int k, n = (1 << D) - 1; //n是最大結點編號 2 ^ D - 1;
		 
		for(int i = 0; i < I; i ++ )
		{
			k = 1;//當前所在位置數 
			for( ; ; )
			{
				s[k] = !s[k];//開關狀態改變 
				k = s[k] ? k * 2 : k * 2 + 1;//
				if(k > n) break;//已經落"出界"了 
			}
		}
		printf("%d\n", k / 2); //"出界"之前的葉子編號 
	} 
	return 0;
}

數組模擬的方法需要開闢的數組非常大,可以根據小球編號的奇偶性,直接模擬最後一個小球的路線。當I爲奇數,它是往左走的第(I + 1) / 2個小球,當I是偶數時,它是往右走的第I / 2 個小球。

模擬最後一個小球路線

#include<iostream>
#include<cstring> 
using namespace std;
int main() 
{
	int D, I;//葉子深度和小球個數 
	while(~ scanf("%d%d", &D, &I))
	{
		int k = 1;
		for(int i = 0; i < D - 1; i ++ )
		{
			if(I % 2 != 0)//奇數個數的球路線 
			{
				k = k * 2;
				I = (I + 1) / 2; 
			}
			else//偶數個數的球路線
			{
				k = k * 2 + 1;
				I /= 2;
			}
		}
		printf("%d\n", k);
	} 
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章