Шахматную доску ???? × ???? нужно разрезать на ????·???? единичных квадратов.

Шахматную доску ???? × ???? нужно разрезать на ????·???? единичных квадратов. На каждом шаге вы можете сделать либо один горизонтальный, либо один вертикальный разрез. Первый разрез разделит плату на две части; после этого каждый разрез разделяет одну оставшуюся доску на две. Стоимость разреза равна количеству единичных квадратов, оставшихся на меньшей из двух получившихся поддосок. Например, горизонтальный разрез на доске 2 × 3 приводит к получению двух поддосок 1 × 3 и стоит 3, тогда как вертикальный разрез приводит к получению поддосок размером 2 × 1 и 2 × 2 и стоит 2. Затраты складываются. : стоимость последовательности разрезов равна сумме их индивидуальных затрат. Опишите алгоритм для вычисления минимальной общей стоимости сокращения доски ???? × ???? на ее единичные квадраты. Докажите его правильность и продемонстрируйте свой анализ временной сложности.

Мое решение выглядит следующим образом: 1. Я следую жадному подходу, проверяя наибольшее значение между m (строка) и n (столбец) и делая разрез. 2. Если m больше, я делаю вертикальный разрез, а другой - горизонтальный. 3. Это дает мне самую низкую стоимость сокращения на каждом этапе. 4. Я следую принципу «разделяй и властвуй» и рекурсивно следую подходу, пока не получу m x n = 1 x 1.

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

Мое выражение временной сложности: T(mn) = 2 T(mn/2) + theta(n).

Может ли кто-нибудь посоветовать мне, как я могу это сделать?


person Ayan Sengupta    schedule 10.04.2018    source источник
comment
Это то, во что я тоже верю. Но пока не смог доказать это математически, поэтому не заявлял об этом явно. Может быть, если я смогу вывести сложность, я смогу попытаться доказать это.   -  person Ayan Sengupta    schedule 10.04.2018
comment
А, я неправильно понял вопрос.   -  person Daniel McLaury    schedule 10.04.2018


Ответы (2)


Минимальная стоимость (n-1)*m+(m-1)*n. Вы можете получить, сделав m горизонтальных разреза, заплатив за каждый n-1 и n вертикальный разрез, заплатив за каждый m-1. Это алгоритм O(1).

Чтобы отрезать единичный квадрат, нужно заплатить за него минимум 2 в (n-1)*(m-1) случаях, минимум 1 в (n-1)+(m-1), а один единичный квадрат можно получить бесплатно. Это ограничивает общую цену снизу:

2*(n-1)*(m-1)+1*(n-1)+(m-1)+0*1 = 2*n*m-n-m = (n-1)*m+(m-1)*n
person Yola    schedule 10.04.2018

Вот подход к динамическому программированию, который работает в O (m * n * (m + n)).

Для каждого возможного размера w * h подпрямоугольника вычислите стоимость f (w, h) его разрезания на отдельные квадраты. Выберите первый разрез: w * h разрезается либо на a * h и b * h, либо на w * c и w * d. Стоимость разрезания на a * h и b * h составляет min (a, b) * h + f (a, h) + f (b, h). Стоимость разрезания на w * c и w * d составляет w * min (c, d) + f (w, c) + f (w, d). Собрав все это вместе, мы имеем

f (w, h) = min of
                min {for every a such that 0 < a < w}
                    (let b = w - a)
                    min (a, b) * h + f (a, h) + f (b, h)
           and
                min {for every c such that 0 < c < h}
                    (let d = h - c)
                    w * min (c, d) + f (w, c) + f (w, d)

База f (1, 1) = 0.

Мы можем хранить все f (w, h) в виде двумерного массива и вычислять их снизу вверх в двух циклах, например так:

for w = 1, 2, ..., m:
    for h = 1, 2, ..., n:
        calculate f[w][h] by the formula above in O (w + h)

Или напишите рекурсивную функцию с мемоизацией.

Любой из двух подходов будет работать в O (m * n * (m + n)): мы должны вычислить m * n значений, и каждое вычисляется как минимум O (m + n) значений.


Если жадный подход действительно работает (я не знаю), он будет делать это за O (log m + log n). По интуитивному рассуждению, например, если m = 17 и n = 23, то должны рассматриваться следующие прямоугольники:

17 * 23
17 * 11 and 17 * 12
 8 * 11 and  8 * 12 and  9 * 11 and  9 * 12
 8 *  5 and  8 *  6 and  9 *  5 and  9 *  6
 4 *  5 and  4 *  6 and  5 *  5 and  5 *  6
 4 *  2 and  4 *  3 and  5 *  2 and  5 *  3
 2 *  2 and  2 *  3 and  3 *  2 and  3 *  3
 1 *  1 and  1 *  2 and  2 *  1 and  2 *  2
 1 *  1 again

Как мы видим, прямоугольники будут иметь форму (m / 2^x) * (n / 2^y), где x и y находятся между 0 и log_2 (m + n), и округление может идти в любую сторону.

person Gassa    schedule 10.04.2018
comment
Я пытался реализовать ваш алгоритм здесь: repl.it/@gl_dbrqn/BlankFreshLicense, но я получаю 13 вместо f(2,3), где я думаю, что ответ 7. Я что-то неправильно понял? - person גלעד ברקן; 10.04.2018
comment
@גלעדברקן Это базовый случай = 0 вместо 1. Я тоже сделал эту ошибку, но отредактировал ее в течение пятиминутного льготного периода. Оказывается, это обычный ;) . - person Gassa; 10.04.2018
comment
@גלעדברקן И спасибо за фактическую реализацию псевдокода! Кроме того, я хотел бы отметить, что, используя Python 3.2+ или некоторый бэкпорт на Python 2.7, можно получить однострочное запоминание с lrucache. Что мы должны сделать в любом случае для больших размеров, чтобы сделать решение полиномиальным, а не экспоненциальным. - person Gassa; 10.04.2018
comment
Прохладный. Я просто хотел сравнить с жадным, поэтому я не беспокоюсь об эффективности, но спасибо за совет! - person גלעד ברקן; 10.04.2018
comment
К вашему сведению, ваш и Yola, кажется, совпадают для i,j в диапазоне 2-100: repl.it/@gl_dbrqn/ExperiencedUnfoldedBrain< /а> - person גלעד ברקן; 11.04.2018
comment
@Gassa, спасибо за подробное объяснение. Я думал о динамическом программировании, но не пошел на это. Позвольте мне объяснить, почему. Динамическое программирование помогло бы мне рассчитать затраты на сокращение и сохранить их для использования в будущем, что заняло бы постоянное время. Однако в этом сценарии при выполнении разреза вычисление стоимости также занимает постоянное время, поскольку плата размером M x N приведет либо к M x N-1 и 1 x N под-плат, либо к M-1 x N и M x 1 дополнительная плата. Стоимость разреза в любом случае равна M или N, и ее можно вычислить за постоянное время. Что ты думаешь об этом? - person Ayan Sengupta; 11.04.2018
comment
@AyanSengupta Да, теперь, когда я это понимаю, я думаю, что другой ответ Йолы по сути правильный (хотя и незначительно в деталях). И поскольку это теоретическая нижняя граница, динамическое программирование — это излишество. Так что можете вообще не обращать внимания на мой ответ. Единственным преимуществом динамического программирования здесь является то, что этот подход все еще будет работать для других функций стоимости, когда нет очевидного жадного решения. - person Gassa; 11.04.2018