Advertisement
husoski

Matches and numbers proof of concept

Dec 4th, 2022
427
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.87 KB | None | 0 0
  1. import math
  2. import random
  3. import re
  4.  
  5.  
  6. # - - - - Some functions needed later:
  7.  
  8. # "Dot product" (or "linear combination") x dot y = sum(x[i]*y[i]):
  9.  
  10. def dot(x, y):
  11.     return sum(a*b for a,b in zip(x,y))
  12.  
  13. # convert a number n to a k-digit base b number, as a list of ints
  14. # in least-significent-first order:
  15.  
  16. def base_digits(n, b, k):
  17.     result = []
  18.     while len(result) < k:
  19.         n, d = divmod(n, b)
  20.         result.append(d)
  21.     return result
  22.  
  23. # Convert a list of digit counts and a list of digit values to a
  24. # single list with count[i] occurrences of digit[i], sorted in
  25. # descending order:
  26.  
  27. def expand_by_counts(counts, digits):
  28.     result = []
  29.     for (k,d) in zip(counts, digits):
  30.         result.extend([d]*k)
  31.     result.sort(reverse=True)
  32.     return result
  33.  
  34. # - - - - Constants
  35.  
  36. # Number of matches needed to make each digit, 0..9:
  37. DIGIT_SIZE = (6, 2, 5, 5, 4, 5, 6, 3, 7, 6)
  38.  
  39. # In this program, the "value" of a digit is its numerical value from 0 to 9,
  40. # and its "size" is the number of matches (2 to 7) needed to form it.
  41.  
  42.  
  43. # - - - - Read input:
  44.  
  45. t = input("T = ") # list of digits allowed in forming the result
  46. all_digits = [*map(int, t.split())]
  47.  
  48. total_size = int(input("N = ")) # exact number of matches to use
  49.                                 # forming the result number
  50.  
  51.  
  52. # - - - - Solve the problem:
  53.  
  54. # Make a list of sizes of the ava
  55. sizes = [DIGIT_SIZE[d] for d in all_digits]
  56.  
  57. # Make a reduced list of sizes with no duplicates, in ascending order:
  58. r_sizes = sorted(set(sizes))
  59. print(r_sizes, math.lcm(*r_sizes))
  60.  
  61. # For each reduced size, find the largest digit from all_digits with
  62. # that size.  These are the only digits that can appear in the final
  63. # number.
  64. r_digits = [max(d for d in all_digits if DIGIT_SIZE[d] == x) for x in r_sizes]
  65. print(r_digits)
  66.  
  67. # Choose the "min" digit as the smallest size digit in the reduces list and
  68. # separate its value & size from those of the "rest" of the digits.
  69.  
  70. value_min, *rd_rest = r_digits
  71. size_min, *size_rest = r_sizes
  72. nrest = len(rd_rest) # number of "rest" digits
  73.  
  74. result_len = 0      # length of biggest number found  
  75. result_digits = []  # all non-size_min digits in descending order
  76.  
  77. # Let size be one of the digit sizes in size_rest[].  Since size > size_min,
  78. # a digit of that size can't be used more than (size_min - 1) times in the
  79. # final result.  Otherwise you could replace (size_min) of the digits with
  80. # bigger group of smaller-sized digits to get a longer result.
  81.  
  82. # So, each of the "rest" digits can be used from 0 to size_min-1 times.  That
  83. # means there is a maximum of size_min ** len(size_rest) cases to examine.
  84. # The worst case is size_min == 3, with all 4 larger sizes (4-7) present,
  85. # for a maximum of 3**4 = 81 total cases to inspect.
  86. # (This can be reduced to at most 32 cases by considering the LCM of size
  87. # and size_min.  This should be done in a performance-sensitive real
  88. # application, but the code is a bit messier and not done here.)
  89.  
  90. ncases = size_min ** nrest
  91. for case in range(ncases):
  92.     rest_count = base_digits(case, size_min, nrest)
  93.     rest_matches = dot(rest_count, size_rest)
  94.     if (total_size - rest_matches)% size_min != 0 or rest_matches > total_size:
  95.         continue # either not a multiple of size_min left over, or too many
  96.  
  97.     case_len = sum(rest_count) + (total_size - rest_matches) // size_min
  98.     if case_len < result_len: continue # too short, ignore this case
  99.     case_digits = expand_by_counts(rest_count, rd_rest)
  100.     if case_len == result_len:
  101.         # break ties in length by number value
  102.         if case_digits <= result_digits:
  103.             continue
  104.     result_len = case_len
  105.     result_digits = case_digits
  106.  
  107. # Finally, form the result number:
  108.  
  109. final_digits = result_digits + [value_min]*(result_len - len(result_digits))
  110. final_digits.sort(reverse=True)
  111. result = ''.join(str(d) for d in final_digits)
  112. print(result)
  113.  
  114.  
Advertisement
Comments
  • husoski
    1 year
    # text 0.35 KB | 0 0
    1. This is a complete Python program to demonstrate one way to solve the puzzle of making the largest number possible by forming individual digits from matchsticks (in 7-segment LED style), but using only a give restricted set of digits and *exact* number of matches to use. The method is explained in comments. The code is only lightly tested, so bugs may remain.
Add Comment
Please, Sign In to add comment
Advertisement