http://projecteuler.net/index.php?section=problems&id=26
Analysis
How do we find when a cycle occurs in the decimal representation of a unit fraction? The expansion of 1 divided by 14 is 0.0(714285), Let's see step by step what happens while expanding 1 divided by 14:
Note: dividend = previous remainder * 10
dividend | divisor | result | remainder |
10 | 14 | 0 | 10 |
100 | 14 | 7 | 2 |
20 | 14 | 1 | 6 |
60 | 14 | 4 | 4 |
40 | 14 | 2 | 12 |
120 | 14 | 8 | 8 |
80 | 14 | 5 | 10 |
100 | 14 | 7 | 2 |
20 | 14 | 1 | 6 |
60 | 14 | 4 | 4 |
40 | 14 | 2 | 12 |
... | ... | ... | ... |
Here are a some additional facts that can help to find the solution:
- If the remainder at some point is 0, the decimal representation of the unit fraction is finite.
- For a unit fraction 1/d, the length of the cycle must be smaller than d, since there are at most d-1 possible remainders. As soon as we find a repeater remainder, we find the cycle.
- Because the problem just requires d smaller than 1000, we can start verifying values of d in decreasing order. If at some point we find a cycle of length x, we know we do not need to check values of d smaller than or equal to x, because those values of d cannot create a larger cycle.
1 package cspuzzles; 2 3 public class ProjectEuler26 { 4 // We use this array to map from remainder to the first position where the 5 // remainder was found. For example, for 1/14 = 0.0(714285) 6 // indexOfRemainder[10] = 0; 7 // indexOfRemainder[2] = 1; 8 // indexOfRemainder[6] = 2; 9 // indexOfRemainder[4] = 3; 10 // indexOfRemainder[12] = 4; 11 // indexOfRemainder[8] = 5; 12 // In this problem, we just need up to 1000 entries. 13 private int[] indexOfRemainder = new int[1000]; 14 15 private void solve(){ 16 int d = 999; // we inspect values of d in decreasing order 17 int longestCycle = 1; // minimum value of d to inspect 18 int solution = -1; 19 int index = 0; 20 int remainder = 0; 21 22 // This loop is to check possible values of d. 23 // When d is smaller than the longestCycle, there is no need 24 // to continue checking 25 while(d > longestCycle){ 26 cleanMap(); 27 // the initial numerator is 1, and this is also the 28 // initial remainder because we are working with unit fractions 29 remainder = 1; 30 index = 0; 31 // This loop is to find the cycle for a given value of d 32 while(remainder != 0) { 33 // compute new remainder 34 remainder = (remainder * 10) % d; 35 // check if we have found a cylce 36 if(remainder == 0){ 37 // there is no cycle 38 } 39 else if(indexOfRemainder[remainder] == -1){ 40 // first time we find this remainder 41 indexOfRemainder[remainder] = index; 42 } 43 else { 44 // THE CYCLE!!! 45 // the length of the cycle is the current index minus 46 // the index where the current remainder was previouly found 47 longestCycle = index - indexOfRemainder[remainder]; 48 solution = d; 49 remainder = 0; // break the while 50 } 51 index++; 52 } 53 d--; 54 } 55 System.out.println("Solution: " + solution); 56 System.out.println("Cycle length: " + longestCycle); 57 } 58 59 private void cleanMap(){ 60 for(int i = 0; i < indexOfRemainder.length; i++) 61 indexOfRemainder[i] = -1; 62 } 63 64 public static void main(String[] args){ 65 new ProjectEuler26().solve(); 66 } 67 }Do you like this kind of puzzles? Share your opinion in the comments.
No comments:
Post a Comment