Euler Problem 12

It’s been a long time since I have worked on any of the Euler problems.  I simply haven’t had time.  Well, it was time to spend a bit of time just exercising the math part of my mind, and solve another problem.

Problem 12 asks you to find the first triangle number that has more than 500 divisors.

Like my other C# solutions, it makes sense to decompose this problem into smaller sets. First, figure out how to generate the triangle numbers. Then, figure out the simplest way to determine how many divisors a number has.

Let’s start with the triangle numbers. The nth triangle number is the sum of all natural numbers less than or equal to N. You can think of them like the number of balls in a billiard rack with N rows:  1, (1+2), (1+2+3), (1+2+3+4), or, 1,3,6,10,15…

A little bit of math (or a quick search) will tell you that the Nth triangle number is [N * (N+1)]/2.

Now, all we need to do is compute the total number of divisors for each of these numbers. One simple answer is to take all number less than or equal to the triangle number. Any of those that divide into the triangle number is a divisor. But, that’s incredibly inefficient. Instead, you can stop at Sqrt(Number). That will give you exactly 1/2 the number of divisors. For example, if 128 is divisible by 2, you’ve found two divisors: 2, and 64. Therefore, this method tells me quickly how many divisors a number has:

   1: static int CountDivisors(int n)
   2: {
   3:     var divisors = from val in Enumerable.Range(1, (int)Math.Sqrt(n))
   4:                    where n % val == 0
   5:                    select val;
   6:  
   7:     return divisors.Count()*2;
   8: }

This query (written in two parts) finds the answer. Remember that one of the keys to LINQ is deferred execution. Only the triangle numbers up to and including the answer are generated.  The entire program runs in a few seconds:

 

   1: var triangleNumbers = from n in Enumerable.Range(1, 100000)
   2:                       let Value = (n * (n + 1)) / 2
   3:                       select new
   4:                       {
   5:                           Number = Value,
   6:                           NumDivisors = CountDivisors(Value)
   7:                       };
   8: var answer = (from vals in triangleNumbers
   9:              where vals.NumDivisors > 500
  10:                   select vals).First();

It feels good to stretch the math muscles again.

Published 23 March 2009 01:18 PM by wwagner
Filed under: , ,
Ads by Lake Quincy Media

Comments

# Chris Lomont said on 31 March, 2009 09:35 AM

Your CountDivisors functions fails for square numbers. Try it in n=4 for example. You overcounted the middle divisor. It is not even true that all triangular numbers cannot be square.

Also by making the range go to sqrt(n)+1 instead of sqrt(n) you make more mistakes. For example you miscount 2,6,12,20,30,42,...

# george byrkit said on 03 April, 2009 08:48 AM

I think that Chris is right!  The upper bound of the range should be sqrt(n).  There is no need to round it up for integer conversion, as sqrt(n) produces the correct value for a 'square' number, and sqrt(n)+1 only introduces counting errors.  sqrt(n) for a non-square number is high enough to search!

Then the whole question comes as to whether it's 'unique' divisors, in which case the sqrt(n) of a square number is counted twice, which could be right or wrong...

Search

Go

Blog Group Links

Nascar style badges