Это код гольф. Победителем является действительный код с наименьшим количеством байтов.
Вызов
Учитывая входные данные M и N , ширину и высоту прямоугольной сетки квадратов, выведите многоугольник, который удовлетворяет следующему:
- Ребра многоугольника состоят только из квадратных ребер: диагональных ребер нет - все они вертикальные или горизонтальные.
- Многоугольник не имеет отверстий: каждый квадрат за пределами многоугольника может быть достигнут с помощью ортогональных шагов на квадратах за пределами многоугольника, начиная с квадрата за пределами многоугольника на внешней границе прямоугольника.
- Многоугольник не имеет самопересечения: из ребер квадрата, встречающихся в вершине, не более 2 может быть частью периметра многоугольника.
- Многоугольник связан: любой квадрат в многоугольнике должен быть доступен из любого другого квадрата в многоугольнике с помощью ортогональных шагов, которые остаются внутри многоугольника.
- Полигон имеет максимально возможный периметр: согласно формуле, показанной ниже.
Ваш код должен работать для M и N от 1 до 255.
Формула для максимального периметра
Задача здесь - найти наиболее пригодные для игры в гольф из тех полигонов с максимальным периметром. Максимальный периметр всегда определяется по формуле:
Это верно, потому что для максимального периметра каждая квадратная вершина должна быть по периметру. Для нечетного числа вершин это невозможно, и лучшее, что может быть достигнуто, - это на одну вершину меньше (поскольку периметр всегда четный).
Выход
Выведите форму в виде строки символов, разделенных новой строкой ( N строк ровно из M символов). Здесь я использую пространство для квадратов за пределами многоугольника и '#' для квадратов внутри многоугольника, но вы можете использовать любые два визуально отличных символа, если их значение согласовано для всех входных данных.
Вы можете включить до одной новой строки перевода и до одной новой строки.
Если вы хотите, вы можете вместо этого вывести M строк ровно из N символов, и вы можете выбрать вывод M на N для одних входов и вывод N на M для других.
Примеры
Неверно из-за дыры:
###
# #
###
Неправильно из-за пересечения (касание по диагонали - вершины с 4 квадратными ребрами по периметру) и, кстати, отверстия:
##
# #
###
Недействительно из-за отключения:
#
# #
#
Допустимый полигон с максимальным периметром:
# #
# #
###
кредиты
Сначала я недооценил, как быстро можно рассчитать значение максимального периметра, и собирался просто запросить это значение в качестве выходного. Спасибо замечательным людям в чате, которые объяснили, как определить максимальный периметр для произвольных N и M, и помогли превратить это в испытание, которое будет длиться более одного ответа ...
В частности, благодаря:
Спарр , Згарб , Ферсум , Джимми23013 .
Ответы:
CJam, 47 байтов
Попробуйте онлайн
Объяснение:
Есть два основных случая для результата. Если хотя бы один из размеров является нечетным, шаблон представляет собой простой «рейк». Например, для ввода
7 6
:Если оба размера четные, есть дополнительный столбец, где каждый второй квадрат "включен". Например, для ввода
8 6
:Теперь, чтобы показать, что эти шаблоны достигают теоретического максимума периметра, как указано в описании проблемы, мы должны подтвердить, что первый шаблон имеет периметр
(M + 1) * (N + 1)
, а второй - то же значение минус 1.Для первого шаблона у нас есть периметр с
M
нечетным размером:M
для верхнего края.2
на стороне верхнего ряда.(M - 1) / 2
за щели между зубами.(M + 1) / 2
зубы с периметром2 * (N - 1) + 1
каждый.Это в сумме составляет:
Для второго случая, когда оба
M
иN
являются четными, периметр складывается из:M
для верхнего края.2
на стороне верхнего ряда.M / 2
для открытого # в верхнем ряду.M / 2
зубы с периметром2 * (N - 1) + 1
каждый для простых зубов.2 * (N / 2 - 1)
части периметра для зубцов.Добавляем все это вместе:
источник
Ruby, Rev 1, 66
Используется повышение
m
до 0 0, чтобы решить, 1 илиm
#
будут ли напечатаны s.Используется
>
для проверки последней строки вместо==
.Не могу избавиться ни от места после пут, ни от скобок!
Ruby, Rev 0, 69
Это анонимная лямбда-функция. Используйте это так:
В конце концов, после того, как я спросил, можно ли поменять местами М и N, мне это не нужно.
Типичные выходы для N нечетных. Если мы удалим
#
их самостоятельно с правой стороны, ясно, что у нас будет (N + 1) (M + 1). Включение их в форму удаляет 2 квадрата горизонтального периметра и добавляет 2 квадрата вертикального периметра, поэтому изменений нет.Здесь мы полагаемся на выражение,
"#"*(i%2==0?m:1)
чтобы задать чередующиеся строки из M#
символов и один#
символ, и выравнивание по правому краю для M символов.Типичные выходы для четного N
5 6
явно имеет тот же периметр6 5
, что и приращение M + 1 = 6, по сравнению с5 5
добавлением вертикального периметра из-за зачистки нижнего ряда.6 6
имеет то же самое, что и6 5
плюс приращение (M + 1) -1 = 6 в вертикальном периметре. Таким образом, они соответствуют формуле.Очень удобно, что Ruby
rjust
позволяет вам указать заполнение для пустых ячеек. Обычно для заполнения задано значение," "
но для последней строки мы переключаемся на"# "
(обратите внимание, что заполнение будет необходимо только в последней строке, если N четное. Если N нечетное, последняя строка будет завершена и не будет никакого оправдания, поэтому вы не увидят зубцы.)Проверьте это здесь.
источник
i%2==0
его,i%2<1
чтобы сохранить байт (я сделал это изменение для ссылки на ideone).#
заполнении даже для последнего ряда? Например, на последнем рисунке периметр не совпадает без#
нижнего правого угла?#
просто потому, что это уже способ, которым заканчивается каждая строка, так что это меньше байтов, чем место пробела. (Хотя я не знаю рубина ...)."# "
не" #"
потому, что последний дал бы 2 смежных#
для нечетных M, что определенно нежелательно. 2 соседних#
даже для М не причиняют вреда, поэтому я пошел с этим. Я не пробовалljust
, возможно, можно было бы сделать это более аккуратно, но было бы не так очевидно, что я печатаю ровно M символов в строке.C
10997 байт и корректностьЯ писал свое решение, но @steveverrill опередил меня. Я думал, что поделюсь этим все же, так как я включил доказательство правильности использованной стратегии.
Сокращенный код:
До сокращения:
Стратегия и Доказательство:
Предполагая правильность уравнения максимального периметра (M + 1) (N + 1) - ((M + 1) (N + 1)) mod 2 , следующее объясняет используемую оптимальную стратегию и доказывает ее правильность по индукции:
Для нечетного M мы рисуем форму руки с пальцами M / 2 + 1, например:
Теперь докажем, что эта стратегия оптимальна для всех нечетных M по индукции:
Базовый случай: M = N = 1
Одна ячейка заполнена. Решение является правильным, поскольку (1 + 1) * (1 + 1) = 2 * 2 = 4, а квадрат имеет 4 стороны.
Индукция по ширине:
Предположим, что стратегия формы руки работает для (N, M-2), где M нечетно, то есть его периметр оптимален и равен (N + 1) (M - 2 + 1) + ((M -1) (N + 1)) мод 2 . Теперь покажем, что это будет работать для (N, M) .
Процесс добавления пальца удаляет один край из многоугольника и добавляет 3 + 2N . Например:
Объединяя это с нашей гипотезой, что предыдущий периметр был оптимальным, новый периметр:
Поскольку мы имеем дело с арифметикой по модулю 2,
Таким образом, доказательство того, что увеличение ширины путем добавления пальцев приводит к оптимальному периметру.
Индукция по высоте:
предположим, что стратегия формы руки работает для (N-1, M) , где M нечетно, то есть его периметр является оптимальным и имеет N (M + 1) + ((M + 1) N) mod 2 . Покажем теперь, что это будет работать для (N, M) .
Увеличение высоты кисти просто удлиняет пальцы, расположенные на первом и на каждом другом x-index. Для каждого увеличения высоты каждый палец добавляет два к периметру, и есть (M + 1) / 2 пальца, таким образом, увеличение N приводит к увеличению 2 (M + 1) / 2 = M + 1 в периметр.
Объединяя это с гипотезой, мы получаем, что новый периметр:
Модульная арифметика позволяет нам упростить последний член, чтобы мы получили:
Доказательство того, что решение оптимально для всех N> 0 и нечетного M> 0.
Для четного M мы заполняем доску так же, как и для нечетного M, но мы добавляем символизацию к последнему сегменту, например:
Теперь докажем, что эта стратегия оптимальна.
Индукция для четного M:
предположим, что решение является правильным для (N, M-1) с нечетным M-1 (как было доказано в последнем случае), который имеет оптимальный периметр (N + 1) M - ( М (Н + 1)) мод 2 . Покажем теперь, что это будет работать для (N, M).
Подобно увеличению пальцев, каждая синергетика добавляет два к периметру многоугольника. Общее количество зубцов составляет (N + N mod 2) / 2 , для всего добавленного периметра N + N mod 2 .
Объединяя это с гипотезой, мы получаем, что новый периметр:
У нас есть это
Потому что, если N нечетно, то это сводится к 0 = 0, а если N четно, то сводится к
Таким образом, стратегия оптимальна для всех M, N> 0 .
источник