Skip to main content

Project Euler Problem 68 Solution with Python

Magic 5-gon ring

Consider the following "magic" 3-gon ring, filled with the numbers 1 to 6, and each line adding to nine.

Example magic 3-gon ring

Working clockwise, and starting from the group of three with the numerically lowest external node (4,3,2 in this example), each solution can be described uniquely. For example, the above solution can be described by the set: 4,3,2; 6,2,1; 5,1,3.

It is possible to complete the ring with four different totals: 9, 10, 11, and 12. There are eight solutions in total.

TotalSolution Set
94,2,3; 5,3,1; 6,1,2
94,3,2; 6,2,1; 5,1,3
102,3,5; 4,5,1; 6,1,3
102,5,3; 6,3,1; 4,1,5
111,4,6; 3,6,2; 5,2,4
111,6,4; 5,4,2; 3,2,6
121,5,6; 2,6,4; 3,4,5
121,6,5; 3,5,4; 2,4,6

By concatenating each group it is possible to form 9-digit strings; the maximum string for a 3-gon ring is 432621513.

Using the numbers 1 to 10, and depending on arrangements, it is possible to form 16- and 17-digit strings. What is the maximum 16-digit string for a "magic" 5-gon ring?

The solution for this problem is very simple. We will have to iterate through differnt combinations of numbers to find the solution.

To make it simple for you to understand, first lets take the example of 3-gon ring and solve it.

To fill the 3-gon ring we will need a total of 6 numbers. You can do this as follows:

In [1]:
numbers = [1, 2, 3, 4, 5, 6]

Now consider the following empty 3-gon-ring. As per the rule, sum of numbers on each line should be the same.

Empty 3-gon ring

For our convinience we will name each and every circle with letters - a, b, c, d, e, f and it will look as follows:

3 gon ring with letters for each circle

So a + b + c == d + c + e == f + e + b

Now the concept is very simple.

  • first we will assign numbers to a, b, c
  • Then the number is assigned to d
  • Let us assume that line_sol = a + b + c
  • Now the value of e = line_sol - c - d
  • Value of f = line_sol - e - b

In this way for each and every combination of a, b, c you will get different d, e, f. We will maintain a list of all these combinations as avail_sol so that we can compute the largest value at the end.

In [2]:
# list of all combinations available
avail_sol = []

Now it is easy to imagine having different combinations of a, b, c, d, e, f. It should be noted here that we need only combinations and not permutations. With some iterations we will get the same numbers in a jumbled fashion. To overcome this problem, the question already states the solution - "Working clockwise, and starting from the group of three with the numerically lowest external node", so we will first have to find the numerically external node and then working clockwise arrange the numbers.

To tackle this problem, we will write a function, which will take a, b, c, d, e, f as input and arrange them as per requirement.

In [3]:
def convert_to_num(a, b, c, d, e, f):
    """
        This function will start with the
        numerically lowest external node,
        moving clockwise arrange the numbers
        on the given line.
    """
    big_num = {a:0, d:1, f:2}
    break_num = big_num[min(big_num.keys())]
    nums = [(a, b, c), (d, c, e), (f, e, b)]
    nums = nums[break_num:]+nums[:break_num]
    string = ''
    for num_tup in nums:
        for num in num_tup:
            string += str(num)
    return string

To make sure you understand the above function, we will take the example given in the question. According to the question

  • a - 4
  • b - 3
  • c - 2
  • d - 6
  • e - 1
  • f - 5

So, big_num = {4:0, 6:1, 5:2}

Consider break_num = big_num[min(big_num.keys())]:

big_num.keys() = [4, 6, 5] - only the external nodes

min(big_num.keys()) = 4

big_num[min(big_num.keys())] = 0

nums = [(4, 3, 2), (6, 2, 1), (5, 1, 3)]

nums = nums[0:] + nums[:0] - same as nums in previous step

At the end the value of string will be 432621513. Let us check the same with our function:

In [4]:
convert_to_num(4, 3, 2, 6, 1, 5)
Out[4]:
'432621513'

As we are confident that we can work with a, b, c, d, e, f, we will write a program to generate the required values of magic-gon

In [5]:
# iterate through values of a
for a in numbers:
    # duplicate the numbers list
    # so that we can use it for b
    numbers_b = numbers[:]
    # numbers_b should not have a
    numbers_b.remove(a)
    # iterate through values of b
    for b in numbers_b:
        # duplicate the numbers_b list
        # so that we can use it for c
        numbers_c = numbers_b[:]
        # remove b from numbers_b
        # numbers_c will not have a, b
        numbers_c.remove(b)
        # iterate through values of c
        for c in numbers_c:
            # sum of lines - line_sol
            line_sol = a + b + c
            # duplicate the numbers_c list
            # numbers_d will not have a, b, c
            numbers_d = numbers_c[:]
            numbers_d.remove(c)
            for d in numbers_d:
                # similarly numbers_e
                numbers_e = numbers_d[:]
                numbers_e.remove(d)
                # but according to above image
                # e = line_sol - c - d
                e = line_sol - c - d
                # check if e is in line_e
                # this is to check if the combination
                # of a, b, c will form magic gon
                if e in numbers_e:
                    # create numbers_f
                    numbers_f = numbers_e[:]
                    # numbers_f should only contain
                    # 1 number
                    numbers_f.remove(e)
                    # but according to image
                    # f = line_sol - e - b
                    f = line_sol - e - b
                    # check if f is in numbers_f
                    if f in numbers_f:
                        # convert the combination
                        # using convert_to_num func
                        temp = convert_to_num(a, b, c, d, e, f)
                        avail_sol.append(temp)
In [6]:
print avail_sol
['146362524', '156264345', '164542326', '165354246', '235451613', '165354246', '253631415', '156264345', '164542326', '156264345', '165354246', '146362524', '253631415', '423531612', '432621513', '235451613', '432621513', '146362524', '423531612', '164542326', '423531612', '235451613', '432621513', '253631415']

As you can see, there are a lot of duplicates in the list. This is just because of different arrangements of given numbers.

To find the solution we will have to find the maximum of avail_sol

In [7]:
# solution will be the maximum of all the numbers
sol = max([int(x) for x in avail_sol])
print sol
432621513

Program

In [8]:
# http://radiusofcircle.blogspot.com

# time module
import time

# time at the start of program execution
start = time.time()

# numbers from 1-10
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def convert_to_num(a, b, c, d, e, f, g, h, i, j):
    """
    Function to convert a-j to
    required string based on the criteria
    """
    big_num = {a:0, d:1, f:2, h:3, j:4}
    break_num = big_num[min(big_num.keys())]
    nums = [(a,b,c), (d,c,e), (f,e,g), (h,g,i), (j,i,b)]
    nums = nums[break_num:]+nums[:break_num]
    string = ''
    for num_tup in nums:
        for num in num_tup:
            string += str(num)
    return string

# list to store solutions
avail_sol  = []

# start with all the numbers
for a in numbers:
    numbers_b = numbers[:]
    numbers_b.remove(a)
    # numbers without a
    for b in numbers_b:
        numbers_c = numbers_b[:]
        numbers_c.remove(b)
        # numbers without a, b
        for c in numbers_c:
            line_sum = a+b+c
            numbers_d = numbers_c[:]
            numbers_d.remove(c)
            # numbers without a, b, c
            for d in numbers_d:
                numbers_e = numbers_d[:]
                numbers_e.remove(d)
                e = line_sum - c - d
                # numbers without a, b, c, d
                if e in numbers_e:
                    numbers_f = numbers_e[:]
                    numbers_f.remove(e)
                    # numbers without a, b, c, d, e
                    for f in numbers_f:
                        numbers_g = numbers_f[:]
                        numbers_g.remove(f)
                        g = line_sum - e - f
                        # numbers without a, b, c, d, e, f
                        if g in numbers_g:
                            numbers_h = numbers_g[:]
                            numbers_h.remove(g)
                            # numbers without a, b, c, d, e, f, g
                            for h in numbers_h:
                                numbers_i = numbers_h[:]
                                numbers_i.remove(h)
                                i = line_sum - g - h
                                # check if i is in numbers_i list
                                if i in numbers_i:
                                    j = line_sum - i - b
                                    numbers_j = numbers_i[:]
                                    numbers_j.remove(i)
                                    # numbers without a, b, c, d, e, f, g, h, i
                                    if j in numbers_j:
                                        ctn = convert_to_num(a, b, c, d, e, f, g, h, i, j)
                                        avail_sol.append(ctn)

# solution will be the maximum of all the numbers
sol = max([int(x) if len(x) == 16 else 0 for x in avail_sol])

# print the solution
print "Answer: " , sol

# time at the end
end = time.time()

# total time taken
print "Time taken: " , end - start

The program is very much similar to the one which I have explained above. The program is written keeping the following image in mind:

Magic 5 gon ring with alphabets

Rest of the code is almost same, the only change is the following:

sol = max([int(x) if len(x) == 16 else 0 for x in avail_sol])

As mentioned in the question, we only require numbers which are 16 digits in length. To make it simple we will make all the other numbers 0, then find the largest of all the given numbers.

You can download the above program from here: Github Gist

Summary

I am writing this solution after a very long time. To find the best suitable solution for this problem, it took some time. But it was worth working. As you have already seen, the solution for this problem is straight forward. If we can imagine the concept of the magic gon ring with alphabets, then you are on the right track. You can solve this problem easily. To be frank, a part of the solution has been given in the question itself.

To conclude, even though this code doesn't follow the pep standards, I am satisfied with its execution time. As you can see the program runs in fraction of a second. I am not sure whether this approach will work for higher order magic gon rings but I am sure that it will atleast work for Magic 6, 7 gon rings.

As always, if you have any doubts please feel free to comment in the comment box below and I will be glad to see your comment.

If you have any better program or suggestions or doubts related to anything drop a message at contact me.

Have a nice day.

Popular posts from this blog

Problem 60 Project Euler Solution with python

Prime pair sets The primes 3, 7, 109, and 673, are quite remarkable. By taking any two primes and concatenating them in any order the result will always be prime. For example, taking 7 and 109, both 7109 and 1097 are prime. The sum of these four primes, 792, represents the lowest sum for a set of four primes with this property. Find the lowest sum for a set of five primes for which any two primes concatenate to produce another prime. This problem is j u st a brute force problem. If you have come here because you don't know the limit upto which you will h ave to gener ate the prime numbers t hen go ahe ad and t r y with 10,000 . When I first start ed solving the problem I chose 1 million(beca use most of the problem s on project E uler have this limit ), but it took very long for the computer to fin d the solution. After searching on the internet then I found many people choosing 10, 000 so I have changed my in put f rom 1 million to 10000 and the output was f ast. He...

Add/Embed SVG to Blogger website

In this post I will tell you my method(trick) of adding SVG images in a blogger website or blog. Before starting , the first thin g I am assu m ing is that you are aware of SVG if you are here. If not please see S calable V ec tor G raphics Recently when I tried to embed a SVG image for a post on pygal, I tried uploading the SVG file and blogger Image uploader came up with an error, because of which I had to find some other way.  SVG File upload Error in Blogger  I started sea rc hing Google " Embed SVG in Blogger " . I found blogorrhea , w h ich gave some i nformatio n on add ing SVG directly as a markup , which worked , but I faced another problem using this . Also th is guy has used lot of Javascript which was confusin g for me, being new to using SVG.   So I first t houg ht of learning on h ow to embed SVG in HTML and t his on e worked out. Actually we can embed SVG in HTML i n following ways: Using Object tag Using Iframe tag Using embed...

Making a quiz web app with python and flask

Edit : When you are creating a web app with h tml templates, then y ou will have to sa ve the html file in templates folder in the Current Wor ki ng Directory( CWD). If you save the file in the C W D directl y you will get a TemplateNotFound error. Thank you Udhay for pointing it out.   In this post we will create a quiz website using python . I will be using the flask framework . After reading this tutorial you will learn form submission , flask templates , python code in flask templates , shuffling the questions and options with the random module and few others.  Please note that this tutorial is not big as it seems to be. Some of the code has been rewritten to maintain consistency and also font size is somewhat big so that your eyes won't get stressed reading this tutorial. Also the content has not occupied the full width of the page. In this tutorial I am assuming that you are having a very basic understanding of the flask framework . Please refer the documenta...