有一棵二叉樹,最大深度為d,且所有葉子的深度都相同。所有結點從上到下從左到右編號為1,2,3,...,2^d-1。在結點1處放乙個小球,它會往下落。每個內結點上都有乙個開關,初始全部關閉,當每次有小球落到乙個開關上時,它的狀態都會改變。當小球到達乙個內結點時,如果該結點上的開關關閉,則往左走,否者往右走,直到走到葉子結點。
一些小球從結點1處依次開始下落,最後乙個小球將會落到**呢?輸入葉子深度d和小球個數i,輸出第i個小球最後所在的葉子編號。假設i不超過整棵樹的葉子個數(即2^(d-1))。d<=20。輸入最多包含1000組資料。
樣例輸入:
4 23 4
10 1
2 28 128
16 12345
樣例輸出:127
5123
25536358
[分析]
不難發現,對於乙個結點k,它的左兒子、右兒子的編號分別是2k和2k+1。所以方法[1]可以模擬程式輸出結果。但是這種方法的缺點是:運算量太大,由於小球個數i可以高達2^(d-1),每個測試資料下落總層數可能會高達2^19*(20-1)=9961472。所以效率比較低。
考慮方法[2],每個小球都會落在根結點上,因此前兩個小球必然是乙個在左子樹,乙個在右子樹。一般地,只需看小球的編號的奇偶性,就能知道它是最終在哪棵子樹中。對於那些落入根結點左子樹的小球來說,只需知道該小球是第幾個落在根的左子樹里的,就可以知道它下一步往左還是往右了。以此類推,直到小球落到葉子上。當i是奇數時,它是往左走的第(i+1)/2個小球;當i是偶數時,它是往右走的第i/2個小球。這樣,可以直接模擬最後乙個小球的路線。這樣,程式的運算量就與小球編號無關了,而且節省了乙個巨大的陣列tree,程式的效率很高。
[1] 通過模擬程式輸出結果。
[cpp]view plain
copy
#include
#include
#include
#include
usingstd::string;
constintmanx=20;
inttree[1<intmain()
29. }
30. end=clock();
31. printf("%d/n",k/2);// the number of node before out of range
32. printf("time used: %lfs/n",(double)(end-beg)/clocks_per_sec);
33. }
34.return0;
35. }
36. /*
37. 16 65535
38. 49151
39. time used: 0.016000s
40. */
[2] 根據規律輸出結果。
[cpp]view plain
copy
#include
#include
#include
#include
usingstd::string;
intmain()
23.else24.
29. }
30. end=clock();
31. printf("%d/n",k);
32. printf("time used: %lfs/n",(double)(end-beg)/clocks_per_sec);
33. }
34.return0;
35. }
36. /*
37. 16 65535
38. 49151
39. time used: 0.000000s
40. */
小球下落(二叉樹)
有一棵二叉樹,最大深度為d,且所有葉子的深度都相同。所有結點從上到下從左到右編號為1,2,3,2 d 1。在結點1處放乙個小球,它會往下落。每個內結點上都有乙個開關,初始全部關閉,當每次有小球落到乙個開關上時,它的狀態都會改變。當小球到達乙個內結點時,如果該結點上的開關關閉,則往左走,否者往右走,直...
二叉樹之小球下落
題目 有一顆二叉樹,最大深度為d,且所有葉子的深度都相同。所有節點從上到下從左到右編號為1,2,3,2 d 1。在節點1處放置乙個小球,它會往下落。每個內節點上都有乙個開關,初始全都關閉,當每次有小球落到乙個開關上時,他的狀態都會改變。當小球到達乙個內節點時,如果該節點上的開關關閉,則往左走,否則往...
二叉樹的編號優化 小球下落
參考 演算法競賽入門經典 每個小球都會落在根節點上,因此前兩個小球必然是乙個在左子樹,乙個在右子樹。一般,只需要知道小球編號的奇偶性,就能知道它是最終在哪棵子樹中。對於那些落入根結點左子樹來說,只需知道該小球是第幾個落在根的左子樹里的,就可以知道它下一步該往左還是往右了。以此類推,直到小球落到葉子結...