Google Code Jam Notes - Rational Number Tree - Java

来源:互联网 发布:ppt数据展示模板 编辑:程序博客网 时间:2024/06/07 11:28
Problem:
Retrieved from: http://code.google.com/codejam/contest/2924486/dashboard#s=p1

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 
 
41 22 1 21 52 3 2
Case #1: 1 2Case #2: 2Case #3: 3 2Case #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, qBigInteger 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 sequenceBigInteger 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 childbits[len] = new BigInteger("1");p = p.subtract(q);} else {// left childbits[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