максимальная длина стороны квадрата меньших квадратов - PullRequest
0 голосов
/ 04 марта 2020

Учитывая 2 числа M и N, где M - квадратные плитки размером 1x1, а N - квадратные плитки размером 2x2, возвращают длину стороны самого большого квадрата, который вы можете создать. если квадрат не может быть создан, верните 0

Пример M = 4, N = 3, возврат 4

enter image description here

Example2 M = 13, N = 3 return 5

enter image description here

Example3 M = 0, N = 18 return 8, используйте 16 плиток 2x2 для создания квадрата. Обратите внимание, что не все плитки используются.

Я решил некоторые случаи, используя

return math.floor(math.sqrt(M+(4*N)))

, но не работал для других случаев

Ответы [ 5 ]

2 голосов
/ 06 марта 2020

Это иногда называют тайлингом . Альтернативный метод для этого - сформулировать математическую модель оптимизации и затем использовать готовый решатель. Не уверен, что это вас интересует, но я упомяну это для полноты.

Вот более сложный пример. Рассмотрим инвентарь плитки:

----     29 PARAMETER input  inventory data

            count       width        area

tile1           6           1           1
tile2           5           2           4
tile3           4           3           9
tile4           3           4          16
tile5           2           5          25
tile6           1           6          36
total          21                     196

Несколько удивительно, но для этого примера мы можем использовать все плитки (в большинстве случаев это не так):

enter image description here

Я использовал формулировку Смешанное целочисленное программирование и использовал стандартные решатели для ее решения. Модель слишком длинная и сложная для воспроизведения здесь. Для подробного описания см ссылка .

2 голосов
/ 04 марта 2020

Я уверен, что кто-то сможет реорганизовать и очистить этот код, но проблема заинтересовала меня достаточно, чтобы попытаться решить ее, прежде чем я отправлюсь на пробежку. Я с нетерпением жду некоторых комментариев о том, как его очистить, но на основе 3 приведенных примеров и ожидаемых ответов этот код, похоже, работает.

Идея в том, что вы превращаете маленькие плитки в максимально возможное количество больших плиток. Затем вы определяете, какой самый большой квадрат вы можете сделать из общих больших плиток (больших и преобразованных маленьких). Как только вы узнаете это, вы определите, сколько из общих больших плиток вы не использовали, и, по возможности, преобразуйте их обратно в маленькие плитки.

Ключевым моментом здесь является то, что если у вас больше запасных больших плиток, чем у маленьких, вы возвращаете все маленькие плитки, поскольку они вам не нужны. Если у вас меньше запасных плиток, чем у маленьких, то вы возвращаете все запасные части, которые вы не использовали в качестве маленьких плиток.

Теперь мы разработали самый большой квадрат, который мы можем сделать из n, мы будем использовать оставшиеся m, чтобы расширить квадрат. Таким образом, чтобы вычислить, сколько м нам нужно, мы вычислим самую длинную длину квадрата, умножим ее на 2 и добавим 1 для угловой части.

теперь мы просто l oop, в то время как у нас больше m, чем нам нужно, чтобы расширить квадрат. каждый раз, когда мы вычитаем эти m из доступных m, увеличиваем самую длинную длину и вычисляем, сколько нам нужно продлить снова.

ОБНОВЛЕНИЕ - Код с измененным рефакторингом, чтобы сделать его более читабельным

import math
from typing import Tuple


def largest_square_num(number: int) -> int:
    while number > 1:
        sqrt = math.sqrt(number)
        if sqrt == int(sqrt):
            break
        else:
            number -= 1
    return number


def convert_m_to_n(m: int) -> Tuple[int, int]:
    n_from_m = m // 4
    m_after_n = m % 4
    return n_from_m, m_after_n


def convert_n_to_m_limit(n: int, limit: int) -> int:
    if n > limit:
        m = limit * 4
    else:
        m = n * 4
    return m


def calulate_largest_side_of_square(m, n):
    # build as many n's from m's and store the new n's and remaining m's
    n_from_m, m_after_n = convert_m_to_n(m)
    total_n = n + n_from_m

    # calculate the largest square that can be made from total n's
    largest_square_of_n = largest_square_num(total_n)
    longest_length = math.sqrt(largest_square_of_n) * 2

    # restore m's back from spare n's but not more than we took from m's
    restored_m = convert_n_to_m_limit(total_n - largest_square_of_n, n_from_m)
    total_m = restored_m + m_after_n

    # now we have the biggest n square extent it while we have enough m's
    while True:
        m_needed_to_extend = longest_length * 2 + 1
        if total_m < m_needed_to_extend:
            break
        total_m -= m_needed_to_extend
        longest_length += 1
    return int(longest_length)


tests = [(4, 3), (13, 3), (1, 2), (9, 1), (0, 0), (5, 1)]
for n, m in tests:
    print(f"{m=}, {n=}, longest_side={calulate_largest_side_of_square(n, m)}")

ВЫХОД

m=3, n=4, longest_side=4
m=3, n=13, longest_side=5
m=2, n=1, longest_side=2
m=1, n=9, longest_side=3
m=0, n=0, longest_side=0
m=5, n=1, longest_side=3
1 голос
/ 19 апреля 2020

Ниже мое Python решение. Кажется, что работает хорошо.

Вот объяснение кода:

Наилучшая возможность найти самый большой квадрат - это использовать все заданные плитки. Таким образом, общая площадь (M * 1 + N * 4) плиток будет равна площади составной фигуры.

Чтобы проверить, составляет ли использование всех плиток квадрат, мы подставляем root общую площадь плиток (math.sqrt (M + N * 4)). Если мы получим значение #integer # из квадрата root, мы можем быть уверены, что составная фигура является самым большим квадратом. Таким образом, одна сторона составного квадрата равна квадрату root от общей площади.

В противном случае мы начинаем удалять плитки (N и M) из составной фигуры одну за другой, пока не достигнем квадратной формы. Во-первых, мы начинаем удалять плитки M, потому что мы знаем, что область плиток M имеет меньшую площадь, чем N. Если удаление маленькой плитки (M) приводит нас к квадрату, тогда нет необходимости удалять плитки N.

Если удаление M не приведет нас к квадратной форме, тогда мы начнем удалять плитки N, пока не достигнем квадратной формы и не вернем значение стороны (квадрат root площади)

def solution(M, N):
    side = math.sqrt(M + N*4)
    if side%1 == 0: return int(side)
    else:
        for i in range(M):
            M -= 1
            side = math.sqrt(M + N*4)
            if side%1 == 0: return int(side)
        for i in range(N):
            N -= 1
            side = math.sqrt(M + N*4)
            if side%1 == 0: return int(side)

    return int(side)


1 голос
/ 04 марта 2020

Я думаю, что это должно работать. Я попробовал это на некоторых тестовых примерах, и он возвращает желаемый результат

    import math
    def is_perfect_square(N):
        return math.sqrt(N)%1==0
    def get_side_for_perfect_square(N,M):
        '''
       if N is perfect square we can create exact square of side s=2*sqrt(N)
       using just N . the number of M s needed in oreder to get
       a square with s+i side is then qualculated as 2*(s+i)+1
       '''
       i=0
       side=0

       if N==0:
          if is_perfect_square(M):
              side=math.sqrt(M)
       elif M==0:
           side=math.sqrt(N*4)
       else:
           while M>0:
              M-=2*(math.sqrt(N*4)+i)+1
              if M==0:
                  side=math.sqrt(N*4)+i+1
                  break
              i+=1
       return side
    def size_of_square(N,M):
        perfect_square=is_perfect_square(N)
        side=0
        if not perfect_square:
            '''
            if N is not perfect square we have to find the next perfect square
            that can be created using just N and then the number of M needed to
            create that next perfect square is calculate by finding the
            difference between N and next perfect square. 
            after that if there is M remaining we should analyze it 
            with get_side_for_perfect_square(new_N,new_M) function where 
            new_N and new_M are the corresponding values after the above
            calculation
            '''
            tiles_in_N=4*N
            next_square=(int(math.sqrt(N))+1)**2
            tiles_next_square=next_square*4
            empty_space=tiles_next_square - tiles_in_N
            M-=empty_space
            if M==0:
                side=2*math.sqrt(next_square)
            elif M>0:
                side=get_side_for_perfect_square(next_square,M)
        else:
            side=get_side_for_perfect_square(N,M)
        return int(side)
1 голос
/ 04 марта 2020

N = 4 с M = 5 не сработает, даже если общая площадь равна 25. Чтобы сделать эту работу, все числа должны быть квадратными числами (4,9,16, ... (НЕ 1)). Вам нужно написать что-то, что может проверить, может ли преобразование 4M в N превратить оба в указанные квадратные числа. Я отредактирую это, когда закодирую.


import math

def squareSize(M,N):
    squares =[0,4,9,16,25,36,49,64,81,100]

    if M in squares:
        if N in squares:
            print(1)
            return math.sqrt(M+(4*N))
    if N in squares:
        if M not in squares:
            print(2)
            return(0)
    if M in squares:
        if N not in squares:
            print(3)
            while (M >= 5):
                M = M - 4
                N = N + 1
                if M in squares:
                    if N in squares:
                        return math.sqrt(M+(4*N))
                break
            if M == 1:
                print(1)
                return(0)
            if M == 2:
                print(2)
                return(0)
            if M == 3:
                print(3)
                return(0)    
            if M == 4:
                if N in squares:
                    return math.sqrt(M+(4*N))
                else:
                    M = 0
                    N = N + 1
                    if N in squares:
                        return math.sqrt(M+(4*N))
                    else:
                        return(0)

    if M not in squares:
        if N not in squares:
            print(4)
            while (M >= 5):
                M = M - 4
                N = N + 1
                if M in squares:
                    if N in squares:
                        return math.sqrt(M+(4*N))
                break
            if M == 1 or 2 or 3:
                return(0)
            if M == 4 or 0:
                if N in squares:
                    return math.sqrt(M+(4*N))

Это скажет вам, можете ли вы создать квадрат со всеми доступными фигурами.

Я только что понял, что вы также хотите, чтобы можно было создать меньшую, не используя все части, - просто добавьте al oop, который проходит проверку программы с меньшими комбинациями M & N, пока не найдете одну, надеюсь, это помогает.

...