Google Code Jam Notes - Rational Number Tree - Java

Problem:

Consider an infinite complete binary tree where the root node is 1/1 and left and right childs of node p/q are p/(p+q) and (p+q)/q, respectively. This tree looks like:

         1/1
    ______|______
    |           |
   1/2         2/1
 ___|___     ___|___
 |     |     |     |
1/3   3/2   2/3   3/1
...
It is known that every positive rational number appears exactly once in this tree. A level-order traversal of the tree results in the following array:
1/1, 1/2, 2/1, 1/3, 3/2, 2/3, 3/1, ...

Please solve the following two questions:

  1. Find the n-th element of the array, where n starts from 1. For example, for the input 2, the correct output is 1/2.
  2. Given p/q, find its position in the array. As an example, the input 1/2 results in the output 2.

Input

The first line of the input gives the number of test cases, TT test cases follow. Each test case consists of one line. The line contains a problem id (1 or 2) and one or two additional integers:

  1. If the problem id is 1, then only one integer n is given, and you are expected to find the n-th element of the array.
  2. If the problem id is 2, then two integers p and q are given, and you are expected to find the position of p/q in the array.

Output

For each test case:

  1. If the problem id is 1, then output one line containing "Case #x: p q", where x is the case number (starting from 1), and pq are numerator and denominator of the asked array element, respectively.
  2. If the problem id is 2, then output one line containing "Case #x: n", where x is the case number (starting from 1), and n is the position of the given number.

Limits

1 ≤ T ≤ 100; p and q are relatively prime.

Small dataset

1 ≤ npq ≤ 216-1; p/q is an element in a tree with level number ≤ 16.

Large dataset

1 ≤ npq ≤ 264-1; p/q is an element in a tree with level number ≤ 64.

Sample


Input 
 

Output 
 
4
1 2
2 1 2
1 5
2 3 2
Case #1: 1 2
Case #2: 2
Case #3: 3 2
Case #4: 5

Analysis:
The trick is to map the Rational Number Tree to another complete binary tree as:
                         1
                     10   11
            100  101   110   111
You can see in this tree, left child is to append 0 the end of parent node, right child is to append 1 to the parent node. And each binary number value just represents the position:(1, 10(2), 11(3), 100(4), 101(5)..)

Then, since left child is p/(p+q), right child is (p+q)/q, so:

1. when p/q is given, if p >q, it is the left child (0), if p<q, it is the right child (1). Also we can calculate their parent's value. By calculating this repeatedly, until we get the root child 1/1, we can get a successive binary numbers, their value is the position.

2. when position is given. we can convert this value to binary representation, then we can generate the p/q step by step according to the complete binary tree we built.

Time complexity: O(log(n)). 

My solution: (Your opinion is highly appreciated)

package codeJam.google.com;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;

/**
 * @author Zhenyi 2013 Dec 21, 2013 17:56:56 PM
 */
public class RationalNumberTree {
	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(
				"C:/Users/Zhenyi/Downloads/B-small-practice.in"));
		FileWriter out = new FileWriter(
				"C:/Users/Zhenyi/Downloads/B-small-practice.out");
		// BufferedReader in = new BufferedReader(new FileReader(
		// "C:/Users/Zhenyi/Downloads/B-large-practice.in"));
		// FileWriter out = new FileWriter(
		// "C:/Users/Zhenyi/Downloads/B-large-practice.out");

		Integer T = new Integer(in.readLine());
		for (int cases = 1; cases <= T; cases++) {
			String[] st = in.readLine().split("\\s");
			Integer choice = new Integer(st[0]);

			if (choice.equals(1)) {
				// find p, q
				BigInteger n = new BigInteger(st[1]);
				BigInteger p = new BigInteger("1");
				BigInteger q = new BigInteger("1");
				int len = 0;
				BigInteger[] bits = new BigInteger[65];
				while (!n.equals(new BigInteger("0"))) {
					bits[len] = n.mod(new BigInteger("2"));
					n = n.divide(new BigInteger("2"));
					len++;
				}
				if (len == 1) {
					out.write("Case #" + cases + ": 1 1" + "\n");
				} else {
					for (int i = len - 2; i >= 0; i--) {
						if (bits[i].equals(new BigInteger("0"))) {
							q = q.add(p);
						}

						if (bits[i].equals(new BigInteger("1"))) {
							p = p.add(q);
						}
					}
					out.write("Case #" + cases + ": " + p + " " + q + "\n");
				}

			} else {
				// find sequence
				BigInteger n = new BigInteger("0");
				BigInteger p = new BigInteger(st[1]);
				BigInteger q = new BigInteger(st[2]);
				BigInteger root = new BigInteger("1");
				BigInteger[] bits = new BigInteger[65];
				int len = 0;
				while (!(p.equals(root) && q.equals(root))) {
					if (p.subtract(q).signum() > 0) {
						// right child
						bits[len] = new BigInteger("1");
						p = p.subtract(q);

					} else {
						// left child
						bits[len] = new BigInteger("0");
						q = q.subtract(p);
					}
					len++;
				}
				bits[len] = new BigInteger("1");
				len++;

				if (len == 1) {
					out.write("Case #" + cases + ": 1" + "\n");
				} else {
					for (int i = len - 1; i >= 0; i--) {
						n = n.multiply(new BigInteger("2")).add(bits[i]);
					}
					out.write("Case #" + cases + ": " + n + "\n");
				}

			}

		}

		in.close();
		out.flush();
		out.close();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值