UVa 679 例題6-6 小球下落(Dropping Balls)
阿新 • • 發佈:2019-01-22
題目大意:
有一顆滿二叉樹,每個節點是一個開關,初始全是關閉的,小球從頂點落下,小球每次經過開關就會把它的狀態置反,現在問第k個球下落到d層時經過的開關編號。
解題思路:
這道題一開始看的時候,感覺不是很複雜,看了題目就開始自己實現了。
(程式碼一)一開始(為什麼說一開始,因為後面還有另一方法啊!)思路很直接,就是用一個2^m大小的陣列來模擬二叉樹,第i個位置的左右節點分別是i*2和i*2+1.然後模擬從1到n個小球的下落過程。最後就能順利獲得最後一個小球的下落位置了。(程式碼一)
(非重點,吐槽)是不是很簡單?昂?當時感覺真爽啊!寫完一個bug都沒啊!直接出正確結果啊!debug都不用啊!果然寫水題很有成就感啊!然後就準備提交,為了以防萬一我還在 Udebug上找了一組輸入測試了一下。通過!爽!然後就提交了,心裡默想不AC我直播吃屎。(劃掉,為什麼要劃掉呢,因為我沒說過啊,哈哈哈)然後,然後,然後就TLE了。(你在逗我吧,怎麼可能不AC,一定是OJ出毛病了,爛OJ,恩,絕對是這樣。)然後我就去看紫書上的程式碼,這麼思路完全和我的一樣啊,那為毛不能AC啊,吃屎吧!然後直到我開始翻下一頁,MMP,竟然還可以這樣,吃屎吧你。。。
(程式碼二)另一種更優的思路是,當一個小球在某個結點時,可以直接根據該小球是第幾個落在該結點上的來判斷他的下落方向,如果是如果是奇數則應該落到他的左結點,如果是奇數則應該落到他的有節點。而且每個結點上小球落上去的平均次數是隨著層數減半的。根據這些原理就能夠直接求最後一個小球的下落路徑。從而減少一層迴圈的時間,也減少了一個表示二叉樹的超大陣列。
感悟:
看來簡單的題也不一定簡單啊。(doge臉)程式碼:
程式碼一:
#include<stdio.h> #include<string.h> using namespace std; const int MAXN = 524288 + 100; int tree[MAXN]; int main() { //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); int num,n, m; while(scanf("%d",&num) == 1 && num !=-1) { while (num--) { scanf("%d %d",&n,&m); int ball; memset(tree, 0, sizeof(tree)); for (int i = 0; i < m; i++) { ball = 1; for (int j = 1; j < n; j++) { int b = ball; if (tree[ball]) ball = 2 * ball + 1; else ball = 2 * ball; tree[b] = !tree[b]; } } printf("%d\n",ball); } } return 0; }
程式碼二:
#include<iostream>
using namespace std;
int main()
{
int num,n, m;
while(cin >> num && num !=-1)
{
while (num--)
{
cin >> n >> m;
int ball = 1;
for (int j = 1; j < n; j++)
{
if (m % 2)
{
ball = ball * 2;
m = (m + 1) / 2;
}
else
{
ball = ball * 2 + 1;
m = m / 2;
}
}
cout << ball << endl;
}
}
return 0;
}