poj2499 Binary Tree

先上題目:

9:Binary Tree

總時間限制: 
1000ms 
內存限制: 
65536kB
描述
Background
Binary trees are a common data structure in computer science. In this problem we will look at an infinite binary tree where the nodes contain a pair of integers. The tree is constructed like this:
  • The root contains the pair (1, 1).
  • If a node contains (a, b) then its left child contains (a + b, b) and its right child (a, a + b)

Problem
Given the contents (a, b) of some node of the binary tree described above, suppose you are walking from the root of the tree to the given node along the shortest possible path. Can you find out how often you have to go to a left child and how often to a right child?
輸入
The first line contains the number of scenarios.
Every scenario consists of a single line containing two integers i and j (1 <= i, j <= 2*109) that represent
a node (i, j). You can assume that this is a valid node in the binary tree described above.
輸出
The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line containing two numbers l and r separated by a single space, where l is how often you have to go left and r is how often you have to go right when traversing the tree from the root to the node given in the input. Print an empty line after every scenario.
樣例輸入
3
42 1
3 4
17 73
樣例輸出
Scenario #1:
41 0

Scenario #2:
2 1

Scenario #3:
4 6
來源
TUD Programming Contest 2005 (Training Session), Darmstadt, Germany

經分析,有以下四點:
1.給定一個pair,例如(left, right),那麼在這棵樹裏,除根結點(1, 1)之外,其他節點的left!=right。

2.那麼,(left, right)是如何得來的呢?因爲left!=right,若left>right,則(left, right)一定是由(left-right, right)向左轉得來的,若left<right,則(left, right)一定是由(left, right-left)向右轉得來的。就這樣倒推回(1, 1),分別統計向左轉、向右轉的次數即可。

從這裏我們也可以看出,除(1, 1)、(1, right)和(left, 1)三種情況之外,left與right不可互相整除。

3.最壞情況下的時間複雜度是O(N),例如一直從左路向上回溯。

4.和二叉樹關係不大。

上代碼:
#include <iostream>
using namespace std;

int main()
{
	int n, i;
	int left, right;
	int l_turn, r_turn;

	freopen("D:\\in.txt", "r", stdin);
	freopen("D:\\out.txt", "w", stdout);

	cin>>n;
	for (i=0; i<n; ++i)
	{
		cin>>left;
		cin>>right;

		l_turn=0;
		r_turn=0;

		while (left!=1 || right!=1)
		{
			if(left>right)
			{
				left-=right;
				++l_turn;
			}
			else
			{
				right-=left;
				++r_turn;
			}
		}

		cout<<"Scenario #"<<i+1<<":"<<endl;
		cout<<l_turn<<' '<<r_turn<<endl;
		cout<<endl;
	}

	return 0;
}

提交上去,wtf?!,time limited exceeded,要知道最壞情況下的複雜度也不過是O(N)啊!再看題目,輸入數據“ i and j (1 <= i, j <= 2*109”,上十億規模了,如果測試數據中有(2000000000, 1),則要做幾乎20億次常數時間的操作,顯然不可能在1000ms內完成,所以必須改進。

幸好改進的方法也足夠簡單:用除法代替減法。
#include <iostream>
using namespace std;

int main()
{
	int n, i;

	int left, right;
	int l_turn, r_turn;

	freopen("D:\\in.txt", "r", stdin);
	freopen("D:\\out.txt", "w", stdout);

	cin>>n;
	for (i=0; i<n; ++i)
	{
		cin>>left;
		cin>>right;

		l_turn=0;
		r_turn=0;

		while (left!=1 || right!=1)
		{
			if(left == 1)	//left是1,right肯定不是1;相當於一直從右路回溯  
			{
				r_turn += right-1;
				right = 1;
			}
			else if(right == 1)	//right是1,left肯定不是1;相當於一直從左路回溯
			{
				l_turn += left-1;
				left = 1;
			}
			else	//都不是1,則較大數除以較小數;且最終餘數一定會是1
			{
				if(left>right)
				{
					l_turn += left/right;
					left %= right;
				}
				else
				{
					r_turn += right/left;
					right %= left;
				}
			}
		}

		cout<<"Scenario #"<<i+1<<":"<<endl;
		cout<<l_turn<<' '<<r_turn<<endl;
		cout<<endl;
	}

	return 0;
}

這樣就ac了。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章