← Problem 60

Cyclical figurate numbers

Problem 62 →

Cyclical figurate numbers

Problem 61

Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:
The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.
  • The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).
  • Each polygonal type: triangle (P3,127=8128), square (P4,91=8281), and pentagonal (P5,44=2882), is represented by a different number in the set.
  • This is the only set of 4-digit numbers with this property.
  • Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.
    # 45 - 141
    def triangle(n):
        return n * (n + 1) / 2
    
    
    # 32 - 101
    def square(n):
        return n**2
    
    
    # 26 - 82
    def pentagonal(n):
        return n * (3 * n - 1) / 2
    
    
    # 23 - 71
    def hexagonal(n):
        return n * (2 * n - 1)
    
    
    # 21 - 64
    def heptagonal(n):
        return n * (5 * n - 3) / 2
    
    
    # 19 - 59
    def octagonal(n):
        return n * (3 * n - 2)
    
    
    ranges = [(45, 141), (32, 101), (26, 82), (23, 71), (21, 64), (19, 59)]
    funs = [triangle, square, pentagonal, hexagonal, heptagonal, octagonal]
    
    
    def build_map():
        data = {}
        for i in range(6):
            fun = funs[i]
            for j in range(ranges[i][0], ranges[i][1]):
                v = fun(j)
                p = str(v / 100)
                # the value map under this prefix
                vs = data.setdefault(p, {})
    
                # the value map for the specified prefix and under current index
                vis = vs.setdefault(i, [])
                vis.append(v)
        return data
    
    
    data = build_map()
    
    
    def find(idx_list, value, result):
        r = value % 100
        if r > 10:
            prefix = str(r)
            if len(idx_list) == 6:
                if str(result[0] / 100) == prefix:
                    # print idx_list, result
                    print sum(result)
            else:
                # get value map under the prefix
                vs = data.setdefault(prefix, {})
    
                # the value map for the specified prefix and under current index
                for idx, vis in vs.items():
                    if not idx in idx_list:
                        for vi in vis:
                            find(idx_list + [idx], vi, result + [vi])
    
    
    def run():
        for i in range(ranges[5][0], ranges[5][1]):
            v = funs[5](i)
            find([5], v, [v])