У меня есть n x m
матрица, состоящая из неотрицательных целых чисел. Например:
2 3 4 7 1
1 5 2 6 2
4 3 4 2 1
2 1 2 4 1
3 1 3 4 1
2 1 4 3 2
6 9 1 6 4
«Сбрасывание бомбы» уменьшает на единицу число целевой ячейки и всех восьми ее соседей до минимума нуля.
x x x
x X x
x x x
Что такое алгоритм, который бы определял минимальное количество бомб, необходимое для сокращения всех ячеек до нуля?
Вариант Б (из-за того, что я не внимательный читатель)
На самом деле, первая версия проблемы не та, на которую я ищу ответ. Я не внимательно прочитал всю задачу, есть дополнительные ограничения, скажем так:
Как насчет простой проблемы, когда последовательность в строке не должна увеличиваться:
8 7 6 6 5
возможна входная последовательность
7 8 5 5 2
невозможно, так как 7 -> 8 растет в последовательности.
Возможно, поиск ответа для «более простого» случая поможет найти решение для более сложного.
PS: я считаю, что когда у нас несколько одинаковых ситуаций, требующих минимального количества бомб для очистки верхней линии, мы выбираем тот, который использует большинство бомб с «левой стороны» ряда. Все еще есть доказательства, которые могут быть верными?
источник
what's the minimum amount of bombs required to clean the board?
таков : означает ли это, что не обязательно нужно искать фактическую схему бомбардировки, а просто минимальное количество бомб?Ответы:
Есть способ свести это к простой подзадаче.
Объяснение состоит из двух частей: алгоритм и причина, по которой алгоритм обеспечивает оптимальное решение. Первое не имеет смысла без второго, поэтому я начну с «почему».
Если вы думаете о бомбардировке прямоугольника (предположим, большой прямоугольник - без краевых случаев), вы можете увидеть, что единственный способ уменьшить полый прямоугольник квадратов по периметру до 0 - это бомбить либо периметр, либо бомбить полый прямоугольник квадраты только внутри периметра. Я назову слой периметра 1, а прямоугольник внутри него слоем 2.
Важное понимание заключается в том, что нет точечного бомбардировочного слоя 1, потому что «радиус взрыва», который вы получаете при этом, всегда содержится в радиусе взрыва другого квадрата от слоя 2. Вы должны быть в состоянии легко убедить себя в этом.
Таким образом, мы можем свести проблему к поиску оптимального способа бомбардировки периметра, тогда мы можем повторять это, пока все квадраты не станут равными 0.
Но, конечно, это не всегда найдет оптимальное решение, если можно будет бомбардировать периметр менее чем оптимальным способом, но при использовании X дополнительных бомб упрощается проблема уменьшения внутреннего слоя с помощью> X бомб. Итак, если мы назовем слой разрешения первым, если мы разместим дополнительные X бомб где-нибудь в слое 2 (только внутри слоя 1), сможем ли мы уменьшить усилие последующей бомбардировки слоя 2 более чем на X? Другими словами, мы должны доказать, что можем быть жадными в уменьшении внешнего периметра.
Но мы знаем, что можем быть жадными. Потому что никакая бомба в слое 2 не может быть более эффективной в уменьшении слоя 2 до 0, чем стратегически размещенная бомба в слое 3. И по той же причине, что и раньше - всегда есть бомба, которую мы можем разместить в слое 3, которая затронет каждый квадрат слоя 2, что бомба, помещенная в слой 2, может. Таким образом, нам никогда не повредит быть жадным (в этом смысле жадным).
Итак, все, что нам нужно сделать, - это найти оптимальный способ уменьшить разрешитель до 0 путем бомбардировки следующего внутреннего слоя.
Мы никогда не пострадаем от первой бомбардировки угла до 0, потому что только угол внутреннего слоя может достичь его, поэтому у нас действительно нет выбора (и любая бомба по периметру, которая может достичь угла, имеет радиус взрыва, содержащийся в радиус взрыва от угла внутреннего слоя).
Как только мы это сделаем, квадраты по периметру, прилегающие к углу 0, могут быть достигнуты только через 2 квадрата от внутреннего слоя:
В этот момент периметр фактически представляет собой замкнутую одномерную петлю, потому что любая бомба уменьшит 3 соседних квадрата. За исключением некоторых странностей возле углов - X может «ударить» по A, B, C и D.
Теперь мы не можем использовать трюки с радиусом взрыва - ситуация каждого квадрата симметрична, за исключением странных углов, и даже там, где радиус взрыва не является подмножеством другого. Обратите внимание, что если бы это была линия (как обсуждает полковник Паник) вместо замкнутого цикла, решение тривиально. Конечные точки должны быть уменьшены до 0, и это никогда не повредит вам бомбить точки, смежные с конечными точками, опять же, потому что радиус взрыва является надмножеством. Как только вы сделали свою конечную точку 0, у вас все еще есть новая конечная точка, поэтому повторяйте (пока линия не станет все 0).
Итак, если мы можем оптимально уменьшить один квадрат в слое до 0, у нас есть алгоритм (потому что мы сократили цикл и теперь имеем прямую линию с конечными точками). Я считаю, что бомбардировка рядом с квадратом с наименьшим значением (что дает вам 2 варианта), так что максимальное значение в пределах 2 квадратов этого минимального значения является минимально возможным (вам, возможно, придется разделить бомбардировку, чтобы справиться с этим), будет оптимальным, но я нет (пока?) доказательств.
источник
But, we do know we can be greedy...
- Я не покупаю это. Посмотрим1 1 2 1 1 2
по периметру. Минимальное количество бомб - 4, но есть три различных решения. Каждое решение по-разному влияет на следующий слой. Пока существует несколько минимальных решений для периметра, вы не можете полностью изолировать периметр без учета внутренних слоев. Я действительно не думаю, что эту проблему можно решить без возврата.0011100
0100010
0000000
0000000
1110111
. Оптимальный способ бомбить первый слой - это бомбить в середине второго ряда, взяв всего три бомбы, чтобы убить внешний слой. Но тогда вам нужно две бомбы, чтобы позаботиться о следующем слое. Оптимальный требует всего четыре бомбы: две для первых двух рядов и две для последнего ряда.Поля говорит: «Если вы не можете решить проблему, то есть более простая проблема, которую вы можете решить: найти ее».
Очевидной более простой проблемой является одномерная задача (когда сетка представляет собой одну строку). Давайте начнем с самого простого алгоритма - жадно бомбить самую большую цель. Когда это идет не так?
Учитывая
1 1 1
, что жадный алгоритм безразличен, в какую ячейку он бомбит первым. Конечно, центральная ячейка лучше - она обнуляет все три ячейки одновременно. Это предполагает новый алгоритм А, «бомба, чтобы минимизировать оставшуюся сумму». Когда этот алгоритм не работает?Учитывая
1 1 2 1 1
, алгоритм A безразличен между бомбардировкой 2-й, 3-й или 4-й ячейки. Но бомбить 2-ю ячейку, чтобы уйти0 0 1 1 1
, лучше, чем бомбить 3-ю ячейку, чтобы уйти1 0 1 0 1
. Как это исправить? Проблема с бомбардировкой 3-й камеры заключается в том, что она оставляет нам работу слева и справа, что должно быть сделано отдельно.Как насчет «бомбы, чтобы минимизировать оставшуюся сумму, но максимизировать минимум слева (от того, где мы бомбили) плюс минимум справа». Назовите этот алгоритм B. Когда этот алгоритм работает не так?
Изменить: После прочтения комментариев, я согласен, гораздо более интересная проблема будет изменена одномерная проблема, так что концы соединяются. Хотелось бы увидеть какой-либо прогресс в этом.
источник
Мне пришлось остановиться только на частичном решении, так как у меня не было времени, но, надеюсь, даже это частичное решение даст некоторое представление об одном потенциальном подходе к решению этой проблемы.
Столкнувшись с трудной проблемой, мне нравится придумывать более простые проблемы, чтобы развить интуицию о проблемном пространстве. Здесь первый шаг, который я предпринял, состоял в том, чтобы превратить эту двумерную задачу в одномерную. Рассмотрим строку:
Так или иначе, вы знаете, что вам нужно будет бомбить
4
4 раза или около этого места, чтобы уменьшить его до 0. Так как слева от пятна находится меньшее число, нет никакой выгоды в том, чтобы бомбить0
или4
перебрасывать бомбу2
. На самом деле, я верю (но не в строгом доказательстве), что бомбардировка2
до тех пор, пока4
точка не опустится до 0, по крайней мере так же хороша, как и любая другая стратегия, чтобы4
снизить ее до 0. В стратегии можно двигаться вниз по линии слева направо. как это:Пара образцов заказов бомбардировки:
Идея начать с числа, которое так или иначе должно уменьшаться, является привлекательной, потому что внезапно становится возможным найти решение, которое, как некоторые утверждают, является, по крайней мере, таким же хорошим как и все другие решения.
Следующий шаг в сложности, где поиск хотя бы хорошего , все еще возможен, находится на краю доски. Для меня ясно, что никогда не будет никакой строгой выгоды бомбить внешний край; вам лучше бомбить спот один и получить три других места бесплатно. Учитывая это, мы можем сказать, что бомбардировка кольца внутри края, по крайней мере, так же хороша, как бомбардировка края. Более того, мы можем объединить это с интуицией, что бомбардировка правого внутри ребра на самом деле является единственным способом уменьшить пространство ребер до 0. Более того, определить оптимальную стратегию тривиально просто (поскольку не хуже, чем любая другая стратегия) уменьшить число углов до 0. Мы сложим все это вместе и сможем приблизиться к решению в двумерном пространстве.
Учитывая наблюдение за угловыми фигурами, мы можем с уверенностью сказать, что мы знаем оптимальную стратегию перехода от любой стартовой доски к доске с нулями на всех углах. Это пример такой доски (я позаимствовал числа из двух линейных досок выше). Я пометил некоторые пробелы по-разному, и я объясню почему.
Заметим, что в верхнем ряду очень похоже на линейный пример, который мы видели ранее. Вспоминая наше предыдущее наблюдение, что оптимальный способ получить верхний ряд до 0 - это бомбить второй ряд (
x
ряд). Нет никакого способа очистить верхний ряд, бомбя любой изy
рядов, и нет никакой дополнительной выгоды от бомбардировки верхнего ряда по сравнению с бомбардировкой соответствующего пространства вx
ряду.Мы могли бы применить линейную стратегию сверху (бомбардировать соответствующие пробелы в
x
ряду), касаясь только верхнего ряда и ничего больше. Было бы что-то вроде этого:Недостаток такого подхода становится очень очевидным в последних двух бомбардировках. Понятно, учитывая, что единственными местами бомб, которые уменьшают
4
число в первом столбце во втором ряду, являются первыйx
и второйy
. Последние две бомбардировки явно уступают первой бомбардировкеx
, что было бы точно так же (в отношении первого места в верхнем ряду, которое у нас нет другого способа очистки). Поскольку мы продемонстрировали, что наша текущая стратегия является неоптимальной, явно необходима модификация стратегии.На этом этапе я могу сделать шаг назад по сложности и сосредоточиться только на одном углу. Давайте рассмотрим это:
Это ясно , что единственный способ получить пространство с
4
до нуля, чтобы бомбить некоторую комбинациюx
,y
иz
. С некоторой акробатикой в моем уме, я вполне уверен, что оптимальное решение - бомбитьx
три раза, аa
затемb
. Теперь нужно выяснить, как я достиг этого решения, и если оно покажет какую-то интуицию, которую мы можем использовать, чтобы даже решить эту локальную проблему. Я заметил, что там нет бомбежекy
иz
пробелов. Попытка найти угол, где бомбардировка этих мест имеет смысл, дает угол, который выглядит следующим образом:Для этого ясно, что оптимальным решением является бомбардировка
y
5 раз иz
5 раз. Давайте сделаем еще один шаг вперед.Здесь он чувствует себя так же интуитивно , что оптимальное решение бомбить
a
и вb
6 раз , а затемx
4 раза.Теперь это игра о том, как превратить эту интуицию в принципы, на которых мы можем опираться.
Надеюсь, продолжение будет продолжено!
источник
Для уточненного вопроса простой жадный алгоритм дает оптимальный результат.
Сбросьте бомбы A [0,0] в ячейку A [1,1], затем сбросьте бомбы A [1,0] в ячейку A [2,1] и продолжите этот процесс вниз. Чтобы убрать левый нижний угол, сбросьте макс (A [N-1,0], A [N-2,0], A [N-3,0]) бомбы в ячейку A [N-2,1]. Это полностью очистит первые 3 столбца.
При таком же подходе очистите столбцы 3,4,5, затем столбцы 6,7,8 и т. Д.
К сожалению, это не помогает найти решение исходной проблемы.
«Большая» задача (без ограничения «без увеличения») может оказаться NP-трудной. Вот набросок доказательства.
Предположим, у нас есть планарный граф степени до 3. Давайте найдем минимальное покрытие вершин для этого графа. Согласно статье в Википедии, эта проблема является NP-трудной для плоских графов степени до 3. Это может быть доказано сокращением от Planar 3SAT. А твердость Planar 3SAT - снижением с 3SAT. Оба эти доказательства представлены в недавних лекциях "Алгоритмические нижние оценки" проф. Эрик Демейн (лекции 7 и 9).
Если мы разделим некоторые ребра исходного графа (левый граф на диаграмме), каждый с четным числом дополнительных узлов, результирующий граф (правый граф на диаграмме) должен иметь точно такое же минимальное покрытие вершин для исходных вершин. Такое преобразование позволяет выровнять вершины графа по произвольным позициям на сетке.
Если мы помещаем вершины графа только в четные строки и столбцы (таким образом, что никакие два ребра, падающие на одну вершину, не образуют острый угол), вставляем «единицы» везде, где есть ребро, и вставляем «нули» в другие позиции сетки, мы могли бы использовать любое решение для исходной задачи, чтобы найти минимальное покрытие вершин.
источник
Вы можете представить эту проблему как задачу целочисленного программирования . (это только одно из возможных решений этой проблемы)
Имея очки:
можно написать 16 уравнений, где для точки f, например, выполняется
минимизируется сумма всех индексов и целочисленное решение.
Решение, конечно, сумма этих показателей.
Это можно еще больше упростить, установив все значения xi на границах 0, поэтому в этом примере вы получите уравнение 4 + 1.
Проблема в том, что для решения таких проблем нет тривиального алгоритма. Я не эксперт в этом, но решить эту проблему, так как линейное программирование - трудная задача.
источник
Это частичный ответ, я пытаюсь найти нижнюю границу и верхнюю границу, которая могла бы быть возможным количеством бомб.
В плате размером 3х3 и меньше решение всегда является ячейкой с наибольшим номером.
В досках размером более 4х4 первая очевидная нижняя граница - это сумма углов:
как бы вы ни расставляли бомбы, невозможно очистить эту доску 4х4 с менее чем 2 + 1 + 6 + 4 = 13 бомбами.
В других ответах упоминалось, что размещение бомбы на втором углу для устранения угла никогда не бывает хуже, чем размещение бомбы на самом углу, поэтому с учетом доски:
Мы можем обнулить углы, поместив бомбы на второй угол, чтобы дать новую доску:
Все идет нормально. Нам нужно 13 бомб, чтобы очистить углы.
Теперь соблюдайте числа 6, 4, 3 и 2, отмеченные ниже:
Там нет никакого способа бомбить любые два из этих ячеек одной бомбой, поэтому минимальная бомба увеличилась на 6 + 4 + 3 + 2, поэтому, добавив к числу бомб, которые мы использовали для очистки углов, мы получаем, что минимум Количество бомб, необходимых для этой карты, составило 28 бомб. Невозможно очистить эту карту с менее чем 28 бомбами, это нижняя граница для этой карты.
Вы можете использовать жадный алгоритм, чтобы установить верхнюю границу. Другие ответы показали, что жадный алгоритм дает решение, которое использует 28 бомб. Поскольку ранее мы доказали, что ни одно оптимальное решение не может иметь менее 28 бомб, следовательно, 28 бомб действительно являются оптимальным решением.
Когда жадность и способ найти минимальную границу, о которой я упоминал выше, не сходятся, я думаю, вам нужно вернуться к проверке всех комбинаций.
Алгоритм нахождения нижней границы следующий:
minimums
список.minimums
список, чтобы получить нижнюю границу.источник
Это был бы жадный подход:
Вычислите матрицу «оценок» порядка n X m, где оценка [i] [j] - это общее вычитание точек в матрице, если позиция (i, j) подвергается бомбардировке. (Максимальное количество баллов - 9, минимальное - 0)
Двигаясь по ряду, найдите и выберите первую позицию с наибольшим количеством очков (скажем, (i, j)).
Бомба (I, J). Увеличьте количество бомб.
Если все элементы исходной матрицы не равны нулю, перейдите к 1.
У меня есть сомнения, что это оптимальное решение.
Редактировать:
Подход Greedy, который я опубликовал выше, хотя и работает, скорее всего, не дает нам оптимального решения. Поэтому я решил добавить некоторые элементы DP к нему.
Я думаю, что мы можем согласиться с тем, что в любой момент времени должна быть выбрана одна из позиций с наивысшим «счетом» (оценка [i] [j] = общая сумма вычета очков, если (i, j) подвергнут бомбардировке). Исходя из этого предположения, вот новый подход:
NumOfBombs (M): (возвращает минимальное количество необходимых взрывов)
Дана матрица M порядка n X m. Если все элементы M равны нулю, вернуть 0.
Рассчитаем «балл» по матрице М.
Пусть k различных позиций P1, P2, ... Pk (1 <= k <= n * m) будут позициями в M с наивысшими баллами.
return (1 + мин (NumOfBombs (M1), NumOfBombs (M2), ..., NumOfBombs (Mk)))
где M1, M2, ..., Mk - результирующие матрицы, если мы бомбим положения P1, P2, ..., Pk соответственно.
Кроме того, если мы хотим, чтобы порядок позиций обнулялся в дополнение к этому, мы должны были бы отслеживать результаты "min".
источник
Ваша новая проблема с неубывающими значениями в строках довольно легко решается.
Обратите внимание, что левый столбец содержит самые высокие цифры. Поэтому любое оптимальное решение должно сначала уменьшить этот столбец до нуля. Таким образом, мы можем выполнить 1-D бомбардировку над этим столбцом, уменьшив каждый элемент в нем до нуля. Мы позволяем бомбам падать на второй столб, чтобы они наносили максимальный урон. Я думаю, что здесь много постов, посвященных 1D делу, поэтому я чувствую себя в безопасности, пропуская это дело. (Если вы хотите, чтобы я это описал, я могу.) Из-за убывающего свойства все три крайних левых столбца будут сведены к нулю. Но мы, вероятно, будем использовать здесь минимальное количество бомб, потому что левый столбец должен быть обнулен.
Теперь, когда левый столбец обнуляется, мы просто обрезаем три крайних левых столбца, которые теперь обнуляются, и повторяем с уменьшенной матрицей. Это должно дать нам оптимальное решение, поскольку на каждом этапе мы используем минимально допустимое количество бомб.
источник
Целочисленное линейное программирование Mathematica с использованием ветвлений и границ
Как уже упоминалось, эта проблема может быть решена с помощью целочисленного линейного программирования (то есть NP-Hard ). Mathematica уже имеет встроенный ILP.
"To solve an integer linear programming problem Mathematica first solves the equational constraints, reducing the problem to one containing inequality constraints only. Then it uses lattice reduction techniques to put the inequality system in a simpler form. Finally, it solves the simplified optimization problem using a branch-and-bound method."
[См. Ограниченная оптимизация Учебник по в Mathematica ..]Я написал следующий код, который использует библиотеки ILP Mathematica. Это удивительно быстро.
Для примера, представленного в задаче:
Выходы
Для тех, кто читает это с жадным алгоритмом
Попробуйте свой код на следующую проблему 10x10:
Здесь это разделено запятыми:
Для этой проблемы мое решение содержит 208 бомб. Вот возможное решение (мне удалось решить это примерно за 12 секунд).
Чтобы проверить результаты, которые дает Mathematica, посмотрите, может ли ваш жадный алгоритм работать лучше.
источник
Нет необходимости преобразовывать задачу в линейные подзадачи.
Вместо этого используйте простой жадный эвристик, который должен бомбить углы , начиная с самого большого.
В данном примере четыре угла: {2, 1, 6, 4}. Для каждого угла нет лучшего движения, чем бомбить ячейку с диагональю угла, поэтому мы точно знаем, что наши первые 2 + 1 + 6 + 4 = 13 бомбардировок должны быть в этих диагональных ячейках. После бомбардировки у нас осталась новая матрица:
После первых 13 взрывов мы используем эвристику для устранения 3 0 2 посредством трех взрывов. Теперь у нас есть 2 новых угла, {2, 1} в 4-м ряду. Мы бомбим тех, еще 3 бомбежки. Мы сократили матрицу до 4 х 4 сейчас. Есть один угол, левый верхний. Мы бомбим это. Теперь у нас осталось 2 угла, {5, 3}. Так как 5 - самый большой угол, мы сначала бомбим 5 бомб, а затем, наконец, бомбим 3 в другом углу. Всего 13 + 3 + 3 + 1 + 5 + 3 = 28.
источник
Это делает поиск в поисках кратчайшего пути (серии бомбардировок) через этот «лабиринт» позиций. Нет, я не могу доказать, что нет более быстрого алгоритма, извините.
источник
Кажется, что подход линейного программирования может быть очень полезным здесь.
Пусть P m xn - матрица со значениями позиций:
Теперь давайте определим матрицу бомб B (x, y) mxn , где 1 ≤ x ≤ m , 1 ≤ y ≤ n, как показано ниже
таким образом, что
Например:
Итак, мы смотрим на матрицу B m xn = [ b ij ], которая
Может быть определена как сумма матриц бомб:
( Q IJ будет тогда количеством бомб, которое мы сбросим в позиции p ij )
p ij - b ij ≤ 0 (чтобы быть более кратким, скажем это как P - B ≤ 0 )
Кроме того, B должен минимизировать сумму .
Мы также можем написать B как некрасивую матрицу впереди:
и так как P - B ≤ 0 (что означает P ≤ B ), мы имеем следующую довольно линейную систему неравенства:
Быть д mn x 1 определяется как
п mn x 1 определяется как
Мы можем сказать, что у нас есть система Система ниже представлена как произведение матриц http://latex.codecogs.com/gif.download?S%5Cmathbf%7Bq%7D&space;%5Cge&space;%5Cmathbf%7Bp%7D быть S млн х Миннесота матрицы на обратном , чтобы решить эту систему. Я не расширил это сам, но я считаю, что это должно быть легко сделать в коде.
Теперь у нас есть минимальная проблема, которая может быть сформулирована как
Я полагаю, что что-то легко, почти тривиально, решить с помощью чего-то вроде симплексного алгоритма (в этом есть довольно крутой документ ). Тем не менее, я почти не знаю линейного программирования (я буду проходить курс об этом на Coursera, но это только в будущем ...), у меня были некоторые головные боли, пытающиеся понять это, и у меня есть огромная внештатная работа, чтобы закончить, поэтому я просто сдавайся здесь. Это может быть , что я сделал что - то неправильно в какой - то момент, или что он не может идти дальше, но я считаю , что это путь в конечном итоге может привести к к решению. В любом случае, я с нетерпением жду ваших отзывов.
(Отдельное спасибо за этот удивительный сайт для создания картинок из выражений LaTeX )
источник
"Despite the many crucial applications of this problem, and intense interest by researchers, no efficient algorithm is known for it.
см. стр. 254. Целочисленное линейное программирование - очень сложная вычислительная проблема. Наша единственная надежда , чтобы быть эффективным является использование внутренних свойств о вашей матрице S. Это не что произвольно в конце концов.Это жадное решение
кажется правильным:Как указано в комментариях, в 2D это не получится. Но, может быть, вы можете улучшить это.
Для 1D:
если есть хотя бы 2 числа, вам не нужно стрелять в крайнее левое положение, потому что стрельба во вторую не хуже . Так что стреляйте во второе, а first не 0, потому что вы должны это сделать. Перейти к следующей ячейке. Не забывай о последней камере.
C ++ код:
Так что для 2D:
Опять же: вам не нужно стрелять в первом ряду (если есть второй). Так что стреляйте ко второму. Решите 1D задачу для первого ряда. (потому что вам нужно сделать его нулевым). Опускаться. Не забудьте последний ряд.
источник
"0110","1110","1110"
. Вам нужен только 1 выстрел, но я считаю, что ваш алгоритм будет использовать 2.Чтобы минимизировать количество бомб, мы должны максимизировать эффект каждой бомбы. Чтобы достичь этого, на каждом шаге мы должны выбрать лучшую цель. Для каждой точки суммирования ее и ее восьми соседей - можно было бы использовать в качестве показателя эффективности бомбардировки этой точки. Это обеспечит близкую к оптимальной последовательность бомб.
UPD : Нужно также учитывать количество нулей, потому что бомбить их неэффективно. На самом деле проблема состоит в том, чтобы минимизировать количество хитированных нулей. Но мы не можем знать, как любой шаг приближает нас к этой цели. Я согласен с идеей, что проблема является NP-полной. Я предлагаю жадный подход, который даст ответ, близкий к реальному.
источник
1010101
,0010100
(верхний ряд, нижний ряд) Ваш подход потребует 3. Это может быть сделан в 2Я считаю, что для минимизации количества бомб вам просто нужно максимизировать количество урона ... для этого нужно проверить область с наибольшей силой ... поэтому сначала вы анализируете поле с ядром 3х3 и проверяете, где сумма сильнее .. и бомба там .. и делай пока поле не ровное .. за это подал ответ 28
источник
Вот решение, которое обобщает хорошие свойства углов.
Давайте предположим, что мы могли бы найти идеальную точку отбрасывания для данного поля, то есть лучший способ уменьшить значение в нем. Затем, чтобы найти минимальное количество бомб, которые нужно сбросить, можно сделать первый набросок алгоритма (код вставлен в копию из реализации ruby):
Задача есть
choose_a_perfect_drop_point
. Во-первых, давайте определимся, что такое идеальная точка отбрасывания.(x, y)
уменьшения значения в(x, y)
. Это может также уменьшить значения в других клетках.(x, y)
(x, y)
(x, y)
являются эквивалентными , если они уменьшают тот же набор клеток.(x, y)
является совершенной , если оно эквивалентно всеми точками максимального падения для(x, y)
.Если есть идеальная точка сброса
(x, y)
, вы не можете уменьшить значение(x, y)
более эффективно, чем сбросить бомбу на одну из идеальных точек опускания(x, y)
.Идеальная точка опускания для данного поля - идеальная точка опускания для любой из его ячеек.
Вот несколько примеров:
Идеальная точка падения для ячейки
(0, 0)
( от нуля индекс)(1, 1)
. Все остальные точки падения для(1, 1)
, то есть(0, 0)
,(0, 1)
и(1, 0)
, снижения меньше клеток.Идеальные каплепадения для ячейки
(2, 2)
( от нуля индекса)(2, 2)
, а также все окружающие клетки(1, 1)
,(1, 2)
,(1, 3)
,(2, 1)
,(2, 3)
,(3, 1)
,(3, 2)
, и(3, 3)
.совершенное падение точки для ячейки
(2, 2)
является(3, 1)
: Это уменьшает значение(2, 2)
, и значение(4, 0)
. Все остальные точки отбрасывания(2, 2)
не максимальны, так как они уменьшаются на одну ячейку меньше. Идеальная точка опускания(2, 2)
также является идеальной точкой опускания(4, 0)
, и это единственная идеальная точка опускания для поля. Это приводит к идеальному решению для этой области (одна капля бомбы).Не существует идеальной точки отбрасывания для
(2, 2)
: И,(1, 1)
и(1, 3)
уменьшение,(2, 2)
и другая ячейка (они являются максимальными точками отбрасывания(2, 2)
), но они не эквивалентны. Тем не менее,(1, 1)
это идеальная точка опускания для(0, 0)
, и(1, 3)
это идеальная точка опускания для(0, 4)
.С этим определением идеальных точек отбрасывания и определенным порядком проверок я получаю следующий результат для примера в вопросе:
Однако алгоритм работает только в том случае, если после каждого шага есть хотя бы одна идеальная точка отбрасывания. Можно построить примеры, где нет идеальных точек сброса:
Для этих случаев мы можем изменить алгоритм так, чтобы вместо идеальной точки отбрасывания мы выбирали координату с минимальным выбором максимальных точек отбрасывания, а затем вычисляли минимум для каждого выбора. В приведенном выше случае все ячейки со значениями имеют две максимальные точки отбрасывания. Например,
(0, 1)
имеет максимальные точки падения(1, 1)
и(1, 2)
. Выбор одного из них, а затем вычисление минимума приводит к следующему результату:источник
Вот еще одна идея:
Давайте начнем с присвоения веса каждому пробелу на доске, чтобы узнать, сколько чисел будет уменьшено, если вы сбросите туда бомбу. Таким образом, если пространство имеет ненулевое число, оно получает точку, а если любое смежное с ним пространство имеет ненулевое число, оно получает дополнительную точку. Таким образом, если есть сетка 1000 на 1000, у нас есть вес, назначенный каждому из 1 миллиона пробелов.
Затем сортируйте список пробелов по весу и бомбите тот, который имеет наибольший вес. Это, так сказать, самая большая отдача от нашего доллара.
После этого обновите вес каждого пространства, на вес которого влияет бомба. Это будет пространство, которое вы бомбили, и любое пространство, непосредственно примыкающее к нему, и любое пространство, непосредственно примыкающее к ним. Другими словами, любое пространство, чье значение могло бы быть уменьшено до нуля в результате бомбардировки, или значение соседнего пространства уменьшилось до нуля.
Затем пересортируйте список пространств по весу. Так как в результате бомбардировки их вес изменился только в небольшом подмножестве пространств, вам не нужно прибегать к полному списку, просто перемещайте их в списке.
Бомба нового места наибольшего веса, и повторите процедуру.
Это гарантирует, что каждая бомбардировка уменьшает как можно больше пробелов (в основном, она поражает как можно меньше пробелов, которые уже равны нулю), поэтому она будет оптимальной, за исключением того, что они могут быть связаны весами. Таким образом, вам может понадобиться сделать некоторое отслеживание назад, когда есть галстук для максимального веса. Однако имеет значение только галстук для наибольшего веса, но не другие галстуки, так что, надеюсь, это не слишком сложно.
Изменить: контрпример Mysticial ниже демонстрирует, что на самом деле это не гарантированно будет оптимальным, независимо от весовых коэффициентов. В некоторых случаях максимально возможное уменьшение веса на данном этапе фактически оставляет оставшиеся бомбы слишком разбросанными, чтобы достигнуть кумулятивного уменьшения после второго шага настолько высокого, насколько вы могли бы иметь с немного менее жадным выбором на первом этапе. Я был несколько введен в заблуждение тем, что результаты нечувствительны к порядку взрывов. Oни являютсянечувствителен к порядку, так как вы можете взять любую серию бомбардировок и переиграть их с самого начала в другом порядке и в итоге получить ту же самую доску. Но из этого не следует, что вы можете рассматривать каждую бомбардировку самостоятельно. Или, по крайней мере, каждая бомбардировка должна рассматриваться таким образом, чтобы учитывать, насколько хорошо она настраивает доску для последующих бомбардировок.
источник
1010101
,0010100
может быть контрпримером, который доказывает, что этот подход неоптимален. Этот подход требует 3. Это может быть сделано в 2.Хорошо, предположим, что мы нумеруем позиции на доске 1, 2, ..., nx m. Любая последовательность сбрасывания бомб может быть представлена последовательностью чисел в этом наборе, где числа могут повторяться. Тем не менее, эффект на доске одинаков, независимо от того, в каком порядке вы сбрасываете бомбы, поэтому любой сброс бомб может быть представлен в виде списка чисел nxm, где первое число представляет количество бомб, сброшенных на позицию 1. второе число представляет количество бомб, сброшенных на позицию 2, и т. д. Давайте назовем этот список чисел nxm «ключом».
Вы можете попытаться сначала вычислить все состояния доски, полученные в результате 1 сброса бомбы, а затем использовать их для вычисления всех состояний доски, полученных в результате 2 падений бомбы, и т. Д., Пока не получите все нули. Но на каждом шаге вы должны кэшировать состояния, используя ключ, который я определил выше, поэтому вы можете использовать эти результаты при вычислении следующего шага (подход «динамического программирования»).
Но в зависимости от размера n, m и чисел в сетке требования к памяти при таком подходе могут быть чрезмерными. Вы можете выбросить все результаты для N сбросов бомб, как только вы рассчитали все результаты для N + 1, так что есть некоторая экономия. И, конечно, вы не можете ничего кешировать за счет того, что это займет гораздо больше времени - подход динамического программирования меняет память на скорость.
источник
Если вам нужно абсолютно оптимальное решение для очистки платы, вам придется использовать классический возврат, но если матрица очень большая, то понадобится много времени, чтобы найти лучшее решение, если вы хотите «возможное» оптимальное решение, вы можете использовать жадный алгоритм , если вам нужна помощь в написании алгоритма, я могу помочь вам
Давай думать об этом, это лучший способ. Сделайте там другую матрицу, сохраните точки, которые вы удаляете, сбросив туда бомбу, затем выберите ячейку с максимальным количеством точек и бросьте туда бомбу, обновите матрицу точек и продолжайте. Пример:
значение ячейки +1 для каждой соседней ячейки со значением выше 0
источник
Грубая сила !
Я знаю, что он неэффективен, но даже если вы найдете более быстрый алгоритм, вы всегда можете проверить этот результат, чтобы узнать, насколько он точен.
Используйте некоторую рекурсию, например так:
Вы можете сделать это более эффективным путем кэширования, если по-разному приводите к одному и тому же результату, вам не следует повторять одни и те же шаги.
Разработать:
если бомбардировка ячейки 1,3,5 приводит к тому же результату, что и бомбардировка ячейки 5,3,1, то вам не следует повторять все последующие шаги снова для обоих случаев, достаточно только 1, вам следует хранить где-то все таблица состояний и использовать ее результаты.
Хэш таблицы статистики может быть использован для быстрого сравнения.
источник
Редактировать: не заметил, что Костек предложил почти такой же подход, так что теперь я настаиваю на более сильном утверждении: если выбираемые углы выбираются так, чтобы они всегда были на самом внешнем слое, то это оптимально.
В примере OP: сброс 2 (как 1 + 1 или 2) на что-либо, кроме 5, не приводит к попаданию в любой квадрат, который попадет на 5. Таким образом, мы просто должны сбросить 2 на 5 (и 6 в левом нижнем углу 1 ...)
После этого есть только один способ, как очистить (в верхнем левом углу) то, что было изначально 1 (теперь 0), и это сбросить 0 на B3 (отличная запись). И так далее.
Только после очистки всех столбцов A и E и 1 и 7 строк, начинайте очистку на один уровень глубже.
Считайте, что очищены только те, которые намеренно очищены, очистка углов значений 0 ничего не стоит и упрощает обдумывание.
Поскольку все бомбы, сброшенные таким образом, должны быть сброшены, и это приводит к очистке полей, это оптимальное решение.
После хорошего сна я понял, что это не так. Рассматривать
Мой подход будет сбрасывать бомбы на B3 и C2, когда падения на B2 будет достаточно
источник
Вот мое решение ... Я пока не буду писать его в коде, так как у меня нет времени, но я считаю, что это должно производить оптимальное количество ходов каждый раз - хотя я не уверен, насколько эффективно это будет при поиске точки для бомбардировки.
Во-первых, как сказал @Luka Rahne в одном из комментариев, порядок, в котором вы бомбите, не важен - только комбинация.
Во-вторых, как утверждают многие другие, бомбардировка 1 по диагонали от углов является оптимальной, поскольку она касается большего количества точек, чем углов.
Это создает основу для моей версии алгоритма: мы можем бомбить «1-off из углов» первым или последним, это не имеет значения (в теории) Мы сначала бомбим их, потому что это облегчает последующие решения (на практике) Мы бомбим точку, которая влияет на большинство точек, одновременно бомбардируя эти углы.
Давайте определим Точки Сопротивления, чтобы они были точками на доске с наибольшим количеством не подлежащих бомбардировке точек + наибольшим числом нулей вокруг них.
точки, не подлежащие бомбардировке, могут быть определены как точки, которых нет в нашей текущей области действия доски, на которую мы смотрим.
Я также определю 4 границы, которые будут обрабатывать нашу область видимости: Top = 0, Left = 0, Bottom = k, right = j. (значения для начала)
Наконец, я определю оптимальные бомбы как бомбы, которые сбрасываются на точки, которые примыкают к точкам сопротивления и касаются (1) самой высокой точки сопротивления и (2) наибольшего количества возможных точек.
Что касается подхода - очевидно, мы работаем извне. Мы сможем работать с 4 «бомбардировщиками» одновременно.
Первые точки сопротивления - это, очевидно, наши углы. Точки «вне границы» не подлежат бомбардировке (за каждым углом есть 5 точек). Таким образом, мы бомбим точки по диагонали один из углов в первую очередь.
Алгоритм:
повторять до тех пор, пока верх = низ и лево = право
Я постараюсь написать актуальный код позже
источник
Вы можете использовать государственное планирование пространства. Например, используя A * (или один из его вариантов) в сочетании с эвристикой,
f = g + h
подобной этой:источник
У меня также 28 ходов. Я использовал два теста для лучшего следующего хода: сначала ход, производящий минимальную сумму для доски. Во-вторых, для равных сумм движение, создающее максимальную плотность, определяется как:
Это Хаскелл. «Решить доска» показывает решение двигателя. Вы можете играть в игру, набрав «основной», затем введите целевую точку, «лучший» для рекомендации или «выйти», чтобы выйти.
РЕЗУЛЬТАТ:
* Main> решаем доска
[(4,4), (3,6), (3,3), (2,2), (2,2), (4,6), (4,6), (2,6), (3,2), (4,2), (2,6), (3,3), (4,3), (2,6), (4,2), (4 , 6), (4,6), (3,6), (2,6), (2,6), (2,4), (2,4), (2,6), (3,6 ), (4,2), (4,2), (4,2), (4,2)]
источник
Кажется, здесь есть недвойственная подходящая подструктура. Рассмотрим следующий пример:
Оптимальное решение для этого случая имеет размер 5, поскольку это размер минимального покрытия вершин 9-цикла его ребрами.
Этот случай, в частности, показывает, что ослабление линейного программирования, которое опубликовали несколько человек, не является точным, не работает, и все эти другие плохие вещи. Я почти уверен, что смогу уменьшить «покрыть вершины моего плоского кубического графа как можно меньшим числом ребер» в вашей задаче, что заставляет меня усомниться, сработает ли какое-либо из жадных / восхождений.
Я не вижу способа решить это за полиномиальное время в худшем случае. Может быть очень умное решение для двоичного поиска и DP, которое я не вижу.
РЕДАКТИРОВАТЬ : я вижу, что конкурс ( http://deadline24.pl ) не зависит от языка; они посылают вам кучу входных файлов, а вы отправляете им выходные данные. Таким образом, вам не нужно что-то, что работает в наихудшем полиномиальном времени. В частности, вы можете посмотреть на вход !
На входе есть несколько небольших случаев. Тогда есть случай 10x1000, случай 100x100 и случай 1000x1000. Все три больших дела очень хорошо себя ведут. Горизонтально смежные записи обычно имеют одинаковое значение. На относительно громоздкой машине я могу решить все случаи с помощью грубого принуждения с помощью CPLEX всего за пару минут. Мне повезло на 1000х1000; Релаксация ЛП имеет интегральное оптимальное решение. Мои решения согласуются с
.ans
файлами, предоставленными в комплекте тестовых данных.Могу поспорить, что вы можете использовать структуру входных данных гораздо более прямым образом, чем я, если вы посмотрите на нее; кажется, что вы можете просто срезать первый ряд, или два, или три несколько раз, пока у вас ничего не останется. (Похоже, что в 1000x1000 все строки не увеличиваются? Я полагаю, отсюда ваша "часть B"?)
источник
Я не могу придумать способ подсчета действительного числа, не рассчитав кампанию бомбардировок, используя мою лучшую эвристику, и надеюсь, что получу разумный результат.
Таким образом, мой метод состоит в том, чтобы вычислить показатель эффективности бомбардировки для каждой ячейки, бомбить ячейку с самым высоким значением, .... повторять процесс, пока я не сгладю все. Некоторые выступают за использование простого потенциального урона (т. Е. От 0 до 9) в качестве метрики, но этого не хватает, колотя по ячейкам с высокой стоимостью и не используя перекрытие повреждений. Я бы вычислил
cell value - sum of all neighbouring cells
, сбросил любое положительное значение на 0 и использовал бы абсолютное значение любого отрицательного значения. Интуитивно понятно, что эта метрика должна сделать выбор, который поможет максимизировать перекрытие урона в ячейках с высоким счетом вместо того, чтобы наносить их непосредственно.Приведенный ниже код достигает полного уничтожения испытательного поля в 28 бомбах (обратите внимание, что использование потенциального ущерба в качестве метрики дает 31!).
Результирующая схема бомбардировки выводится следующим образом (значения полей слева, метрика справа)
источник
Это можно решить с помощью дерева глубины O (3 ^ (n)). Где n - сумма всех квадратов.
Сначала предположим, что решить задачу с деревом O (9 ^ n) тривиально, просто рассмотрим все возможные места бомбардировки. Для примера см. Реализацию Alfe .
Затем поймите, что мы можем работать, чтобы бомбить снизу вверх, и при этом получить минимальную схему бомбардировки.
Этот алгоритм является правильным, потому что
На практике этот алгоритм будет регулярно работать лучше, чем его теоретический максимум, потому что он будет регулярно бомбить соседей и уменьшать размер поиска. Если мы предположим, что каждая бомбардировка уменьшает значение 4 дополнительных целей, тогда наш алгоритм будет работать в O (3 ^ (n / 4)) или приблизительно O (1,3 ^ n).
Поскольку этот алгоритм все еще экспоненциальный, было бы целесообразно ограничить глубину поиска. Мы могли бы ограничить число разрешенных веток некоторым числом, X, и, как только мы окажемся настолько глубокими, мы заставим алгоритм выбрать лучший путь, который он определил до сих пор (тот, который имеет минимальную общую сумму платы в одном из своих терминальных листов). ). Тогда наш алгоритм гарантированно запустится за O (3 ^ X) времени, но не гарантируется получение правильного ответа. Тем не менее, мы всегда можем увеличить X и проверить эмпирически, имеет ли смысл компромисс между увеличением вычислений и лучшими ответами.
источник
оценочная функция, общая сумма:
целевая функция:
уничтожить функцию:
целевая функция:
линейная функция максимизации:
Это не оптимально, но может быть оптимизировано путем поиска лучшей функции оценки.
... но, думая об этой проблеме, я думал, что одна из главных проблем - это когда в какой-то момент заброшенные фигуры оказываются в середине нулей, поэтому я бы выбрал другой подход ... который доминирует над минимальными значениями до нуля, а затем пытаюсь по возможности избегать нулей, что приводит к общей минимизации минимального существующего значения
источник
Вся эта проблема сводится к вычислению расстояния редактирования. Просто вычислите вариант расстояния Левенштейна между данной матрицей и нулевой матрицей, где правки заменяются бомбардировками, используя динамическое программирование для хранения расстояний между промежуточными массивами. Я предлагаю использовать хэш матриц в качестве ключа. В псевдо-Python:
источник
Это был ответ на первый заданный вопрос. Я не заметил, что он изменил параметры.
Создайте список всех целей. Присвойте значение цели, основываясь на количестве положительных значений, на которые воздействует капля (сама и все соседи). Наибольшее значение будет девять.
Сортируйте цели по количеству затронутых целей (По убыванию), с вторичной сортировкой по убыванию по сумме каждой пораженной цели.
Бросьте бомбу на цель с самым высоким рейтингом, затем пересчитайте цели и повторяйте, пока все значения целей не станут равны нулю.
Согласитесь, это не всегда самый оптимальный вариант. Например,
Этот подход потребует 5 бомб, чтобы очистить. Оптимально, однако, вы могли бы сделать это в 4. Тем не менее, чертовски близко, и нет возврата назад. Для большинства ситуаций это будет оптимально или очень близко.
Используя исходные номера задач, этот подход решает 28 бомб.
Добавляем код для демонстрации этого подхода (используя форму с кнопкой):
Класс вам понадобится:
источник
09090
этот подход требует 18 бомб. Это может быть сделано в 9.1010101
,0010100
?