Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decompose an integer in two for grid creation

Tags:

algorithm

Given an integer N I want to find two integers A and B that satisfy A × B ≥ N with the following conditions:

  1. The difference between A × B and N is as low as possible.
  2. The difference between A and B is as low as possible (to approach a square).

Example: 23. Possible solutions 3 × 8, 6 × 4, 5 × 5. 6 × 4 is the best since it leaves just one empty space in the grid and is "less" rectangular than 3 × 8.

Another example: 21. Solutions 3 × 7 and 4 × 6. 3 × 7 is the desired one.

A brute force solution is easy. I would like to see if a clever solution is possible.

like image 923
Eduardo Mauro Avatar asked Aug 25 '10 20:08

Eduardo Mauro


1 Answers

Easy.

In pseudocode

a = b = floor(sqrt(N))

if (a * b >= N) return (a, b)

a += 1
if (a * b >= N) return (a, b)

return (a, b+1)

and it will always terminate, the distance between a and b at most only 1.

It will be much harder if you relax second constraint, but that's another question.

Edit: as it seems that the first condition is more important, you have to attack the problem a bit differently. You have to specify some method to measure the badness of not being square enough = 2nd condition, because even prime numbers can be factorized as 1*number, and we fulfill the first condition. Assume we have a badness function (say a >= b && a <= 2 * b), then factorize N and try different combinations to find best one. If there aren't any good enough, try with N+1 and so on.

Edit2: after thinking a bit more I come with this solution, in Python:

from math import sqrt

def isok(a, b):
  """accept difference of five - 2nd rule"""
  return a <= b + 5

def improve(a, b, N):
  """improve result:
    if a == b:
       (a+1)*(b-1) = a^2 - 1 < a*a
    otherwise (a - 1 >= b as a is always larger)
      (a+1)*(b-1) = a*b - a + b - 1 =< a*b

    On each iteration new a*b will be less,
    continue until we can, or 2nd condition is still met
  """
  while (a+1) * (b-1) >= N and isok(a+1, b-1):
    a, b = a + 1, b - 1

  return (a, b)

def decomposite(N):
  a = int(sqrt(N))
  b = a

  # N is square, result is ok
  if a * b >= N:
    return (a, b)

  a += 1

  if a * b >= N:
    return improve(a, b, N)

  return improve(a, b+1, N)

def test(N):
  (a, b) = decomposite(N)

  print "%d decomposed as %d * %d = %d" % (N, a, b, a*b)

[test(x) for x in [99, 100, 101, 20, 21, 22, 23]]

which outputs

99 decomposed as 11 * 9 = 99
100 decomposed as 10 * 10 = 100
101 decomposed as 13 * 8 = 104
20 decomposed as 5 * 4 = 20
21 decomposed as 7 * 3 = 21
22 decomposed as 6 * 4 = 24
23 decomposed as 6 * 4 = 24
like image 176
phadej Avatar answered Sep 29 '22 13:09

phadej