Mam n x m
macierz składającą się z nieujemnych liczb całkowitych. Na przykład:
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
„Zrzucenie bomby” zmniejsza o jeden liczbę komórki docelowej i wszystkich ośmiu jej sąsiadów do minimum zero.
x x x
x X x
x x x
Jaki jest algorytm, który określałby minimalną liczbę bomb wymaganych do zredukowania wszystkich komórek do zera?
Opcja B (Ze względu na to, że nie jestem uważnym czytelnikiem)
Właściwie pierwsza wersja problemu nie jest tą, na którą szukam odpowiedzi. Nie przeczytałem dokładnie całego zadania, istnieją dodatkowe ograniczenia, powiedzmy:
A co z prostym problemem, gdy sekwencja w rzędzie musi się nie zwiększać:
8 7 6 6 5
możliwa sekwencja wprowadzania
7 8 5 5 2
nie jest możliwe, ponieważ 7 -> 8 rośnie w sekwencji.
Może znalezienie odpowiedzi na „łatwiejszą” sprawę pomogłoby znaleźć rozwiązanie na trudniejsze.
PS: Uważam, że gdy mamy kilka takich samych sytuacji wymagających minimalnej liczby bomb do wyczyszczenia górnej linii, wybieramy taką, która używa większości bomb po „lewej stronie” rzędu. Nadal masz jakiś dowód, który może być poprawny?
źródło
what's the minimum amount of bombs required to clean the board?
czy to oznacza, że niekoniecznie trzeba znaleźć rzeczywisty wzór bombowy, ale tylko minimalną liczbę bomb?Odpowiedzi:
Istnieje sposób, aby zredukować to do prostego pod-problemu.
Wyjaśnienie obejmuje 2 części, algorytm i powód, dla którego algorytm zapewnia optymalne rozwiązanie. Pierwszy nie będzie miał sensu bez drugiego, więc zacznę od tego, dlaczego.
Jeśli myślisz o zbombardowaniu prostokąta (załóż duży prostokąt - nie ma jeszcze skrzynek krawędziowych), możesz zauważyć, że jedynym sposobem na zmniejszenie pustego prostokąta kwadratów na obwodzie do 0 jest zbombardowanie albo obwodu, albo zbombardowanie pustego prostokąta kwadraty na obwodzie. Zadzwonię do warstwy obwodowej 1, a prostokąt w jej warstwie 2.
Ważnym spostrzeżeniem jest to, że nie ma punktu bombardowania warstwy 1, ponieważ uzyskany w ten sposób „promień wybuchu” jest zawsze zawarty w promieniu wybuchu innego kwadratu z warstwy 2. Powinieneś być w stanie łatwo o tym przekonać.
Możemy więc zredukować problem do znalezienia optymalnego sposobu na zbombardowanie obwodu, a następnie możemy to powtarzać, aż wszystkie kwadraty osiągną zero.
Ale oczywiście nie zawsze znajdzie to optymalne rozwiązanie, jeśli możliwe będzie zbombardowanie obwodu w mniej niż optymalny sposób, ale użycie X dodatkowych bomb upraszcza problem zmniejszenia warstwy wewnętrznej o> X bomb. Jeśli więc nazwiemy warstwę permiterową pierwszą, jeśli umieścimy dodatkowe bomby X gdzieś w warstwie 2 (tylko w warstwie 1), czy możemy zmniejszyć wysiłek późniejszego bombardowania warstwy 2 o więcej niż X? Innymi słowy, musimy udowodnić, że możemy być chciwi w zmniejszaniu zewnętrznego obwodu.
Ale wiemy, że możemy być chciwi. Ponieważ żadna bomba w warstwie 2 nigdy nie może być bardziej skuteczna w zmniejszaniu warstwy 2 do 0 niż strategicznie umieszczona bomba w warstwie 3. I z tego samego powodu jak poprzednio - zawsze jest bomba, którą możemy umieścić w warstwie 3, która wpłynie na każdy kwadrat warstwy 2, którą może bomba umieszczona w warstwie 2. Tak więc nigdy nie zaszkodzi nam być chciwym (w tym sensie chciwości).
Więc wszystko, co musimy zrobić, to znaleźć optymalny sposób na zmniejszenie permiter'a do zera poprzez bombardowanie następnej warstwy wewnętrznej.
Najpierw nigdy nas nie boli bombardowanie rogu do zera, ponieważ tylko narożnik warstwy wewnętrznej może do niego dotrzeć, więc naprawdę nie mamy wyboru (a każda bomba na obwodzie, która może dotrzeć do narożnika, ma promień wybuchu zawarty w promień piaskowania od rogu warstwy wewnętrznej).
Gdy to zrobimy, kwadraty na obwodzie sąsiadującym z rogiem 0 można osiągnąć tylko 2 kwadraty od wewnętrznej warstwy:
W tym momencie obwód jest faktycznie zamkniętą pętlą 1-wymiarową, ponieważ każda bomba zmniejszy 3 sąsiednie kwadraty. Z wyjątkiem niektórych dziwności w pobliżu rogów - X może „trafić” A, B, C i D.
Teraz nie możemy używać żadnych sztuczek w promieniu wybuchu - sytuacja każdego kwadratu jest symetryczna, z wyjątkiem dziwnych narożników, i nawet tam żaden promień wybuchu nie jest podzbiorem innego. Zauważ, że gdyby była to linia (jak omawia pułkownik Panic) zamiast zamkniętej pętli, rozwiązanie jest trywialne. Punkty końcowe muszą zostać zmniejszone do 0 i nigdy nie zaszkodzi ci zbombardować punkty przylegające do punktów końcowych, ponieważ promień wybuchu jest nadzbiorem. Po utworzeniu punktu końcowego 0 nadal masz nowy punkt końcowy, więc powtórz (dopóki linia nie będzie równa 0).
Tak więc, jeśli możemy optymalnie zmniejszyć pojedynczy kwadrat w warstwie do zera, mamy algorytm (ponieważ przecięliśmy pętlę i teraz mamy linię prostą z punktami końcowymi). Uważam, że bombardowanie przylegające do kwadratu o najniższej wartości (daje 2 opcje), tak że najwyższa wartość w granicach 2 kwadratów od tej najniższej wartości jest minimalną możliwą (być może będziesz musiał podzielić bombardowanie, aby sobie z tym poradzić) będzie optymalna, ale ja nie masz (jeszcze?) dowodu.
źródło
But, we do know we can be greedy...
- Nie kupuję tego. Zastanów1 1 2 1 1 2
się na obwodzie. Minimalna liczba bomb to 4, ale istnieją trzy różne rozwiązania. Każde rozwiązanie ma inny wpływ na następną warstwę. Dopóki istnieje wiele minimalnych rozwiązań dla obwodu, nie można całkowicie odizolować obwodu bez uwzględnienia wewnętrznych warstw. Naprawdę nie sądzę, że ten problem można rozwiązać bez cofania się.0011100
0100010
0000000
0000000
1110111
. Optymalnym sposobem na zbombardowanie pierwszej warstwy jest zbombardowanie w środku drugiego rzędu, biorąc w sumie trzy bomby, aby zabić zewnętrzną warstwę. Ale wtedy potrzebujesz dwóch bomb, aby zająć się następną warstwą. Optimal wymaga tylko czterech bomb ogółem: dwóch dla pierwszych dwóch rzędów i dwóch dla ostatniego rzędu.Pólya mówi: „Jeśli nie możesz rozwiązać problemu, istnieje łatwiejszy do rozwiązania problem: znajdź go”.
Oczywistym prostszym problemem jest problem 1-wymiarowy (gdy siatka jest pojedynczym rzędem). Zacznijmy od najprostszego algorytmu - łapczywie bombardującego największy cel. Kiedy to pójdzie nie tak?
Biorąc pod uwagę
1 1 1
, chciwy algorytm jest obojętny, do której komórki najpierw bombarduje. Oczywiście środkowa komórka jest lepsza - zeruje wszystkie trzy komórki jednocześnie. Sugeruje to nowy algorytm A, „bomba w celu zminimalizowania pozostałej kwoty”. Kiedy ten algorytm się psuje?Biorąc pod uwagę
1 1 2 1 1
, algorytm A jest obojętny między bombardowaniem 2., 3. lub 4. komórki. Ale bombardowanie drugiej komórki, aby odejść,0 0 1 1 1
jest lepsze niż bombardowanie trzeciej komórki, aby odejść1 0 1 0 1
. Jak to naprawić? Problem z bombardowaniem trzeciej komórki polega na tym, że pozostawia nam pracę w lewo i pracę w prawo, co należy wykonać osobno.Co powiesz na „bombę, aby zminimalizować pozostałą sumę, ale zmaksymalizować minimum w lewo (tam, gdzie zbombardowaliśmy) plus minimum w prawo”. Wywołaj ten algorytm B. Kiedy ten algorytm nie działa?
Edycja: Po przeczytaniu komentarzy zgadzam się, że o wiele bardziej interesującym problemem byłby jednowymiarowy problem zmieniony, tak aby końce się połączyły. Chciałbym zobaczyć wszelkie postępy w tym zakresie.
źródło
Musiałem zatrzymać się tylko na częściowym rozwiązaniu, ponieważ nie miałem czasu, ale mam nadzieję, że nawet to częściowe rozwiązanie zapewnia pewne spostrzeżenia na temat jednego potencjalnego podejścia do rozwiązania tego problemu.
W obliczu trudnego problemu lubię wymyślać prostsze problemy, aby rozwinąć intuicję dotyczącą przestrzeni problemów. Pierwszym krokiem, jaki podjąłem, było zredukowanie problemu 2D do problemu 1-D. Rozważ linię:
W ten czy inny sposób wiesz, że będziesz musiał zbombardować
4
4 razy w miejscu lub w pobliżu miejsca, aby obniżyć go do 0. Ponieważ na lewo od miejsca znajduje się niższa liczba, bombardowanie0
lub4
nadmierne bombardowanie nie przynosi żadnych korzyści2
. W rzeczywistości uważam (ale nie ma ścisłego dowodu), że bombardowanie,2
dopóki4
miejsce nie spadnie do zera, jest co najmniej tak dobre, jak każda inna strategia, aby4
obniżyć to do zera. W strategii można przejść od lewej do prawej lubię to:Kilka przykładowych rozkazów bombardowania:
Pomysł, aby zacząć od liczby, która musi zejść w ten czy inny sposób, jest atrakcyjny, ponieważ nagle staje się możliwe znalezienie rozwiązania, które jak niektórzy twierdzą, że jest co najmniej tak dobre, jak wszystkie inne rozwiązania.
Kolejny krok w złożoności, w którym to wyszukiwanie co najmniej tak dobrego jest nadal możliwe, znajduje się na krawędzi planszy. Jest dla mnie jasne, że zbombardowanie zewnętrznej krawędzi nigdy nie przyniesie żadnych konkretnych korzyści; lepiej zbombarduj jedno miejsce i zdobądź trzy inne miejsca za darmo. Biorąc to pod uwagę, możemy powiedzieć, że bombardowanie pierścienia wewnątrz krawędzi jest co najmniej tak dobre, jak bombardowanie krawędzi. Co więcej, możemy połączyć to z intuicją, że bombardowanie prawej krawędzi jest tak naprawdę jedynym sposobem na zmniejszenie odległości między krawędziami do 0. Co więcej, banalnie proste jest ustalenie optymalnej strategii (ponieważ jest to co najmniej tak dobry, jak każda inna strategia), aby zmniejszyć liczbę rzutów rożnych do 0. Zebraliśmy to wszystko razem i możemy znacznie zbliżyć się do rozwiązania w przestrzeni 2-D.
Biorąc pod uwagę spostrzeżenia na temat elementów narożnych, możemy z całą pewnością stwierdzić, że znamy optymalną strategię przejścia z dowolnej planszy początkowej na planszę z zerami na wszystkich rogach. To jest przykład takiej tablicy (pożyczyłem liczby od dwóch liniowych tablic powyżej). Niektóre spacje oznaczyłem inaczej i wyjaśnię dlaczego.
W górnym rzędzie można zauważyć, że bardzo przypomina liniowy przykład, który widzieliśmy wcześniej. Przywołując naszą wcześniejszą obserwację, że optymalnym sposobem na doprowadzenie górnego rzędu do zera jest zbombardowanie drugiego rzędu (
x
rzędu). Nie ma sposobu na wyczyszczenie górnego rzędu przez zbombardowanie któregokolwiek zy
rzędów i nie ma dodatkowej korzyści z bombardowania górnego rzędu nad bombardowaniem odpowiedniego miejsca wx
rzędzie.My mogliśmy zastosować strategię liniowy z góry (bombardowanie odpowiednie miejsca na
x
wiersz), dotyczące się tylko z górnego rzędu i nic innego. Poszłoby coś takiego:Wada tego podejścia staje się bardzo oczywista w ostatnich dwóch bombardowaniach. Jest jasne, biorąc pod uwagę, że jedynymi miejscami bombowymi, które zmniejszają
4
liczbę w pierwszej kolumnie w drugim rzędzie, są pierwszex
i drugiey
. Ostatnie dwa bombardowania są wyraźnie gorsze od samego bombardowania pierwszegox
, co zrobiłoby dokładnie to samo (w odniesieniu do pierwszego miejsca w górnym rzędzie, którego nie mamy innego sposobu wyczyszczenia). Ponieważ wykazaliśmy, że nasza obecna strategia nie jest optymalna, zmiana strategii jest wyraźnie potrzebna.W tym momencie mogę cofnąć się w kierunku złożoności i skupić się tylko na jednym rogu. Rozważmy to:
Jest oczywiste, że jedynym sposobem, aby dostać się z miejsca
4
na dół do zera są bombardować jakąś kombinacjęx
,y
orazz
. Biorąc pod uwagę niektóre akrobacje, jestem całkiem pewien, że optymalnym rozwiązaniem jestx
trzykrotne bombardowanie, aa
potemb
. Teraz chodzi o ustalenie, w jaki sposób doszedłem do tego rozwiązania i jeśli ujawni to jakąkolwiek intuicję, której możemy użyć, aby rozwiązać ten lokalny problem. Zauważam, że nie ma bombardowaniay
iz
spacji. Próba znalezienia rogu, w którym bombardowanie tych przestrzeni ma sens, daje kąt, który wygląda następująco:W tym przypadku jest dla mnie jasne, że optymalnym rozwiązaniem jest bombardowanie
y
5 razy iz
5 razy. Idźmy o krok dalej.Tutaj wydaje się podobnie intuicyjne, że optymalnym rozwiązaniem jest bombardowanie
a
ib
6 razy, a następniex
4 razy.Teraz staje się grą, w jaki sposób zamienić te intuicje w zasady, na których możemy budować.
Mam nadzieję, że będzie kontynuowany!
źródło
W przypadku zaktualizowanego pytania prosty, zachłanny algorytm daje optymalny wynik.
Zrzuć bomby A [0,0] do komórki A [1,1], a następnie zrzuć bomby A [1,0] do komórki A [2,1] i kontynuuj ten proces w dół. Aby wyczyścić lewy dolny róg, zrzuć bomby maks. (A [N-1,0], A [N-2,0], A [N-3,0]) do komórki A [N-2,1]. Spowoduje to całkowite wyczyszczenie pierwszych 3 kolumn.
Przy takim samym podejściu wyczyść kolumny 3,4,5, a następnie kolumny 6,7,8 itd.
Niestety nie pomaga to w znalezieniu rozwiązania pierwotnego problemu.
Problem „większego” (bez ograniczenia „nie-rosnącego”) może być trudny do NP. Oto szkic dowodu.
Załóżmy, że mamy płaski wykres stopnia do 3. Znajdźmy minimalną osłonę wierzchołków dla tego wykresu. Zgodnie z artykułem Wikipedii problem ten jest trudny w NP dla płaskich wykresów stopnia do 3. Można to udowodnić przez redukcję z Planar 3SAT. I twardość Planar 3SAT - poprzez redukcję od 3SAT. Oba te dowody zostały przedstawione w ostatnich wykładach w „Algorytmicznych dolnych granicach” przez prof. Erik Demaine (wykłady 7 i 9).
Jeśli podzielimy niektóre krawędzie oryginalnego wykresu (lewy wykres na diagramie), każdy z parzystą liczbą dodatkowych węzłów, powstały wykres (prawy wykres na diagramie) powinien mieć dokładnie taką samą minimalną osłonę wierzchołków dla oryginalnych wierzchołków. Taka transformacja pozwala wyrównać wierzchołki wykresu do dowolnych pozycji na siatce.
Jeśli umieścimy wierzchołki wykresu tylko na równych wierszach i kolumnach (w taki sposób, że żadne dwie krawędzie padające na jeden wierzchołek nie tworzą ostrego kąta), wstawimy „jedynki” wszędzie tam, gdzie jest krawędź, i wstawiamy „zera” do innych pozycji siatki, możemy użyć dowolnego rozwiązania pierwotnego problemu, aby znaleźć minimalną osłonę wierzchołków.
źródło
Możesz reprezentować ten problem jako problem programowania liczb całkowitych . (jest to tylko jedno z możliwych rozwiązań tego problemu)
Posiadanie punktów:
można napisać 16 równań, w których na przykład zachowuje się punkt f
zminimalizowane ponad sumę wszystkich indeksów i rozwiązania liczb całkowitych.
Rozwiązaniem jest oczywiście suma tych indeksów.
Można to dodatkowo uprościć, ustawiając wszystkie xi na granicach 0, więc w tym przykładzie otrzymamy równanie 4 + 1.
Problem polega na tym, że nie ma trywialnego algorytmu rozwiązywania takich problemów. Nie jestem w tym ekspertem, ale rozwiązanie tego problemu, ponieważ programowanie liniowe jest trudne.
źródło
To jest częściowa odpowiedź, próbuję znaleźć dolną i górną granicę, która może być możliwą liczbą bomb.
W przypadku płyt 3x3 i mniejszych rozwiązaniem jest zawsze największa numerowana komórka.
Na planszach większych niż 4x4 pierwszą oczywistą dolną granicą jest suma narożników:
bez względu na to, jak zorganizujesz bombę, nie możesz wyczyścić tej planszy 4x4 za pomocą mniej niż 2 + 1 + 6 + 4 = 13 bomb.
W innych odpowiedziach wspomniano, że umieszczenie bomby na drugim rogu w celu wyeliminowania rogu nigdy nie jest gorsze niż umieszczenie bomby na samym rogu, więc biorąc pod uwagę tablicę:
Możemy wyzerować rogi, umieszczając bomby w drugim rogu, aby uzyskać nową deskę:
Na razie w porządku. Potrzebujemy 13 bomb, aby oczyścić rogi.
Teraz obserwuj cyfry 6, 4, 3 i 2 oznaczone poniżej:
Nie ma sposobu na zbombardowanie dwóch komórek za pomocą jednej bomby, więc minimalna bomba wzrosła o 6 + 4 + 3 + 2, więc zwiększając liczbę bomb, których użyliśmy do wyczyszczenia narożników, otrzymujemy to minimum liczba bomb wymaganych na tej mapie stała się 28 bombami. Nie można wyczyścić tej mapy przy użyciu mniej niż 28 bomb, jest to dolna granica dla tej mapy.
Możesz użyć chciwego algorytmu, aby ustalić górną granicę. Inne odpowiedzi wykazały, że zachłanny algorytm wytwarza rozwiązanie wykorzystujące 28 bomb. Ponieważ wcześniej udowodniliśmy, że żadne optymalne rozwiązanie nie może mieć mniej niż 28 bomb, dlatego 28 bomb jest rzeczywiście optymalnym rozwiązaniem.
Kiedy chciwość i metoda znajdowania minimalnej granicy, o której wspomniałem powyżej, nie są zbieżne, myślę, że musisz wrócić do sprawdzania wszystkich kombinacji.
Algorytm znajdowania dolnej granicy jest następujący:
minimums
listy.minimums
listę, aby uzyskać dolną granicę.źródło
To byłoby chciwe podejście:
Oblicz macierz „wyniku” rzędu n X m, gdzie wynik [i] [j] jest całkowitym odjęciem punktów w macierzy, jeżeli pozycja (i, j) jest zbombardowana. (Maksymalny wynik punktu to 9, a minimalny wynik to 0)
Poruszając się mądrze, znajdź i wybierz pierwszą pozycję z najwyższym wynikiem (powiedzmy (i, j)).
Bomb (i, j). Zwiększ liczbę bomb.
Jeśli wszystkie elementy oryginalnej macierzy nie są równe zero, to dostaniesz 1.
Mam jednak wątpliwości, że jest to optymalne rozwiązanie.
Edytować:
Podejście Chciwe, które zamieściłem powyżej, choć działa, najprawdopodobniej nie daje nam optymalnego rozwiązania. Pomyślałem, że powinienem dodać do niego kilka elementów DP.
Myślę, że możemy się zgodzić, że w dowolnym momencie jedna z pozycji o najwyższym „wyniku” (wynik [i] [j] = całkowite odjęcie punktów, jeśli (i, j) jest zbombardowana) musi być ukierunkowana. Począwszy od tego założenia, oto nowe podejście:
NumOfBombs (M): (zwraca minimalną wymaganą liczbę bombardowań)
Biorąc pod uwagę macierz M rzędu n X m. Jeśli wszystkie elementy M są równe zero, to zwróć 0.
Oblicz macierz „score” M.
Niech k odrębnymi pozycjami P1, P2, ... Pk (1 <= k <= n * m), będą pozycjami w M o najwyższych wynikach.
return (1 + min (NumOfBombs (M1), NumOfBombs (M2), ..., NumOfBombs (Mk)))
gdzie M1, M2, ..., Mk są macierzami wynikowymi, jeśli zbombardujemy odpowiednio pozycje P1, P2, ..., Pk.
Ponadto, jeśli chcemy, aby kolejność pozycji nuke była dodatkowo, musielibyśmy śledzić wyniki „min”.
źródło
Twój nowy problem z nie zmniejszającymi się wartościami w wierszach jest dość łatwy do rozwiązania.
Zauważ, że lewa kolumna zawiera najwyższe liczby. Dlatego każde optymalne rozwiązanie musi najpierw zredukować tę kolumnę do zera. W ten sposób możemy wykonać 1-D bombardowanie nad tą kolumną, redukując każdy element w niej do zera. Pozwalamy bombom spaść na drugą kolumnę, aby zadawały maksymalne obrażenia. Myślę, że jest tu wiele postów dotyczących sprawy 1D, więc mogę bezpiecznie pominąć tę sprawę. (Jeśli chcesz, żebym to opisał, mogę.). Ze względu na malejącą właściwość wszystkie trzy skrajnie lewe kolumny zostaną zredukowane do zera. Ale z pewnością użyjemy tutaj minimalnej liczby bomb, ponieważ lewa kolumna musi zostać wyzerowana.
Teraz, gdy lewa kolumna zostanie wyzerowana, po prostu odetniemy trzy kolumny najbardziej lewe, które są teraz wyzerowane i powtórzymy z teraz zmniejszoną macierzą. To musi dać nam optymalne rozwiązanie, ponieważ na każdym etapie używamy możliwej do udowodnienia minimalnej liczby bomb.
źródło
Mathematica Integer Programowanie liniowe przy użyciu odgałęzień
Jak już wspomniano, problem ten można rozwiązać za pomocą programowania liniowego liczb całkowitych (czyli NP-Hard ). Mathematica ma już wbudowaną 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."
[Patrz Samouczek optymalizacji optymalizacji w Mathematica ..]Napisałem następujący kod, który wykorzystuje biblioteki ILP Mathematica. Jest zaskakująco szybki.
Na przykład podany w problemie:
Wyjścia
Dla każdego, kto czyta to za pomocą chciwego algorytmu
Wypróbuj kod dotyczący następującego problemu 10x10:
Tutaj jest rozdzielony przecinkami:
W przypadku tego problemu moje rozwiązanie zawiera 208 bomb. Oto możliwe rozwiązanie (udało mi się to rozwiązać w około 12 sekund).
Jako sposób na przetestowanie wyników, które wytwarza Mathematica, sprawdź, czy Twój chciwy algorytm może zrobić coś lepszego.
źródło
Nie ma potrzeby przekształcania problemu w podproblemy liniowe.
Zamiast tego użyj prostej chciwej heurystyki, która polega na bombardowaniu rogów , zaczynając od największej.
W podanym przykładzie są cztery rogi {2, 1, 6, 4}. Dla każdego rogu nie ma lepszego ruchu niż bombardowanie przekątnej komórki do rogu, więc wiemy, że nasze pierwsze bombardowania 2 + 1 + 6 + 4 = 13 muszą odbywać się w tych ukośnych komórkach. Po bombardowaniu zostaje nam nowa matryca:
Po pierwszych 13 bombardowaniach używamy heurystyki, aby wyeliminować 3 0 2 za pomocą trzech bombardowań. Teraz mamy 2 nowe rogi, {2, 1} w czwartym rzędzie. Bombardujemy te, kolejne 3 bombardowania. Zmniejszyliśmy teraz matrycę do 4 x 4. Jest jeden róg, w lewym górnym rogu. Bombardujemy to. Teraz pozostały nam 2 rogi, {5, 3}. Ponieważ 5 jest największym zakrętem, bombardujemy najpierw, 5 bombardowań, a następnie bombardujemy 3 w drugim rogu. Suma wynosi 13 + 3 + 3 + 1 + 5 + 3 = 28.
źródło
Robi to dogłębne poszukiwanie najkrótszej ścieżki (serii bombardowań) przez ten „labirynt” pozycji. Nie, nie mogę udowodnić, że nie ma szybszego algorytmu, przepraszam.
źródło
Wydaje się, że podejście programowania liniowego może być tutaj bardzo pomocne.
Niech P m xn będzie macierzą z wartościami pozycji:
Teraz zdefiniujmy macierz bomb B (x, y) mxn , z 1 ≤ x ≤ m , 1 ≤ y ≤ n jak poniżej
w taki sposób, że
Na przykład:
Szukamy więc macierzy B m xn = [ b ij ] tego
Można zdefiniować jako sumę macierzy bomb:
( q ij byłoby wtedy liczba bomb , które spadlibyśmy na pozycję p ij )
p ij - b ij ≤ 0 (aby być bardziej prostym, powiedzmy to jako P - B ≤ 0 )
Ponadto B powinien zminimalizować sumę .
Możemy również napisać B jako brzydką macierz przed sobą:
a ponieważ P - B ≤ 0 (co oznacza P ≤ B ) poniżej mamy następujący dość liniowy system nierówności:
Będąc q mn x 1 zdefiniowane jako
p mn x 1 zdefiniowany jako
Możemy powiedzieć, że mamy system Poniższy system reprezentowany jest jako iloczyn macierzy http://latex.codecogs.com/gif.download?S%5Cmathbf%7Bq%7D&space;%5Cge&space;%5Cmathbf%7Bp%7D jest S mn x mn macierz, która ma zostać odwrócona, aby rozwiązać system. Nie rozwinąłem go sam, ale uważam, że powinno to być łatwe do zrobienia w kodzie.
Teraz mamy minimalny problem, który można określić jako
Uważam, że rozwiązanie tego problemu jest proste, niemal trywialne dzięki algorytmowi simpleks (jest na ten temat fajny dokument ). Jednak nie znam prawie żadnego programowania liniowego (wezmę kurs na ten temat na Coursera, ale to dopiero w przyszłości ...), miałem pewne problemy z głową, próbując to zrozumieć i mam ogromną pracę freelancera do ukończenia, więc po prostu się poddaj. Może się okazać, że zrobiłem coś nie tak w pewnym momencie, lub że nie może iść dalej, ale uważam, że ta ścieżka może doprowadzić do w roztworze. Tak czy inaczej, zależy mi na twojej opinii.
(Specjalne podziękowania za tę niesamowitą stronę do tworzenia zdjęć z wyrażeń LaTeX )
źródło
"Despite the many crucial applications of this problem, and intense interest by researchers, no efficient algorithm is known for it.
patrz strona 254. Programowanie liniowe liczb całkowitych jest bardzo trudnym problemem obliczeniowym. Naszą jedyną nadzieją na skuteczność będzie wykorzystanie wewnętrznych właściwości macierzy S. W końcu nie jest to takie arbitralne.To chciwe rozwiązanie
wydaje się poprawne:Jak wskazano w komentarzach, nie powiedzie się w 2D. Ale może możesz to poprawić.
Dla 1D:
Jeśli są co najmniej 2 liczby, nie musisz strzelać do lewej, ponieważ strzelanie do drugiej nie jest gorsze . Strzelaj do drugiego, a pierwszy nie jest równy 0, bo musisz to zrobić. Przejdź do następnej komórki. Nie zapomnij o ostatniej komórce.
Kod C ++:
Tak więc dla 2D:
Znowu: nie musisz strzelać w pierwszym rzędzie (jeśli jest drugi). Strzelaj do drugiego. Rozwiąż zadanie 1D dla pierwszego rzędu. (ponieważ musisz ustawić wartość null). Spadać. Nie zapomnij ostatniego rzędu.
źródło
"0110","1110","1110"
. Potrzebujesz tylko jednego strzału, ale wierzę, że Twój algorytm użyłby 2.Aby zminimalizować liczbę bomb, musimy zmaksymalizować efekt każdej bomby. Aby to osiągnąć, na każdym kroku musimy wybrać najlepszy cel. Za każdy punkt sumujący go i ośmiu sąsiadów - może być wykorzystany jako efektywna ilość bombardowania tego punktu. Zapewni to prawie optymalną sekwencję bomb.
UPD : Powinniśmy również wziąć pod uwagę liczbę zer, ponieważ bombardowanie ich jest nieefektywne. W rzeczywistości problemem jest zminimalizowanie liczby trafionych zer. Ale nie możemy wiedzieć, w jaki sposób jakikolwiek krok przybliża nas do tego celu. Zgadzam się z pomysłem, że problem jest NP-zupełny. Sugeruję chciwe podejście, które da odpowiedź zbliżoną do rzeczywistej.
źródło
1010101
,0010100
(górny rząd, dolny rząd) Twoje podejście będzie wymagało 3. Można to zrobić w 2.Uważam, że aby zminimalizować liczbę bomb, wystarczy zmaksymalizować ilość obrażeń. Aby to się stało, musisz sprawdzić obszar o największej sile. Więc najpierw przeanalizuj pole za pomocą jądra 3x3 i sprawdź, gdzie suma jest silniejszy ... i bombarduje tam ... i robi, dopóki pole nie będzie płaskie .. dla tego pola odpowiedź brzmi 28
źródło
Oto rozwiązanie, które uogólnia dobre właściwości narożników.
Załóżmy, że możemy znaleźć idealny punkt zrzutu dla danego pola, czyli najlepszy sposób na zmniejszenie wartości w nim. Następnie, aby znaleźć minimalną liczbę bomb do zrzucenia, może być pierwszy szkic algorytmu (kod jest wklejany z implementacji ruby):
Wyzwanie jest
choose_a_perfect_drop_point
. Najpierw określmy, czym jest idealny punkt zrzutu.(x, y)
zmniejsza wartość w(x, y)
. Może również zmniejszać wartości w innych komórkach.(x, y)
dla(x, y)
jeżeli zmniejsza wartości w odpowiedniej rozszerzeniem komórek, które b maleje.(x, y)
są równoważne, jeśli zmniejszają ten sam zestaw komórek.(x, y)
jest idealny, jeśli jest równoważny wszystkim maksymalnym punktom zrzutu dla(x, y)
.Jeśli istnieje idealny punkt upuszczenia
(x, y)
, nie można zmniejszyć wartości o(x, y)
efektywniej niż zrzucenie bomby na jeden z idealnych punktów zrzutu(x, y)
.Idealny punkt zrzutu dla danego pola to idealny punkt zrzutu dla dowolnej jego komórki.
Oto kilka przykładów:
Idealny punkt upuszczenia dla komórki
(0, 0)
(indeks zerowy) to(1, 1)
. Wszystkie inne punkty drop dla(1, 1)
, to znaczy(0, 0)
,(0, 1)
i(1, 0)
zmniejsz mniej komórek.Idealny punkt kropli na komórki
(2, 2)
(wskaźnik zera) jest(2, 2)
, jak również wszystkich otaczających komórki(1, 1)
,(1, 2)
,(1, 3)
,(2, 1)
,(2, 3)
,(3, 1)
,(3, 2)
, i(3, 3)
.idealne punkty upuszczenia dla komórki
(2, 2)
to(3, 1)
: Zmniejsza wartość w(2, 2)
, a wartość w(4, 0)
. Wszystkie pozostałe punkty upuszczenia(2, 2)
nie są maksymalne, ponieważ zmniejszają o jedną komórkę mniej. Idealny punkt zrzutu(2, 2)
to również idealny punkt zrzutu(4, 0)
i jest to jedyny idealny punkt zrzutu na polu. Prowadzi to do idealnego rozwiązania dla tego pola (jedna kropla bomby).Nie ma idealnego punktu zrzutu dla
(2, 2)
: Zarówno(1, 1)
i(1, 3)
spadku, jak(2, 2)
i innej komórki (są to maksymalne punkty zrzutu dla(2, 2)
), ale nie są równoważne. Jednakże,(1, 1)
jest to doskonały punkt na spadek(0, 0)
, i(1, 3)
jest doskonałą bazą do spadku(0, 4)
.Dzięki tej definicji idealnych punktów zrzutu i pewnej kolejności kontroli otrzymuję następujący wynik dla przykładu w pytaniu:
Algorytm działa jednak tylko wtedy, gdy po każdym kroku jest co najmniej jeden idealny punkt zrzutu. Możliwe jest budowanie przykładów, w których nie ma idealnych punktów zrzutu:
W takich przypadkach możemy zmodyfikować algorytm, aby zamiast idealnego punktu zrzutu wybrać współrzędną z minimalnym wyborem maksymalnych punktów zrzutu, a następnie obliczyć minimum dla każdego wyboru. W powyższym przypadku wszystkie komórki z wartościami mają dwa maksymalne punkty upuszczenia. Na przykład
(0, 1)
ma maksymalne punkty zrzutu(1, 1)
i(1, 2)
. Wybór jednego, a następnie obliczenie minimum prowadzi do tego wyniku:źródło
Oto kolejny pomysł:
Zacznijmy od przypisania wagi każdemu polu na planszy, ile liczb zostanie zmniejszonych przez zrzucenie tam bomby. Więc jeśli przestrzeń ma niezerową liczbę, otrzymuje punkt, a jeśli dowolna sąsiadująca z nią przestrzeń ma niezerową liczbę, otrzymuje dodatkowy punkt. Więc jeśli istnieje siatka 1000 na 1000, mamy wagę przypisaną do każdego z 1 miliona spacji.
Następnie posortuj listę spacji według wagi i zbombarduj tę o największej wadze. To, że tak powiem, najbardziej zyskuje na naszej złotówki.
Następnie zaktualizuj wagę każdej przestrzeni, na którą bomba ma wpływ. Będzie to przestrzeń, którą zbombardowałeś, i każde pole bezpośrednio do niej przylegające oraz każde pole bezpośrednio do nich przylegające. Innymi słowy, każda przestrzeń, której wartość mogła zostać zmniejszona do zera przez bombardowanie, lub wartość sąsiedniej przestrzeni zmniejszona do zera.
Następnie ponownie posortuj spacje listy według wagi. Ponieważ bombardowanie zmieniło tylko niewielką część przestrzeni, nie trzeba uciekać się do całej listy, wystarczy przesunąć te na liście.
Bombarduj nową przestrzeń o największej masie i powtórz procedurę.
Gwarantuje to, że każde bombardowanie redukuje jak najwięcej pól (w zasadzie uderza w jak najmniejszą liczbę pól, które już są zerowe, jak to możliwe), więc byłoby optymalne, z tym wyjątkiem, że mogą to być remisy. Więc może być konieczne wykonanie śledzenia wstecznego, gdy istnieje remis dla najwyższej wagi. Liczy się tylko remis dla najwyższej wagi, a nie inne remisy, więc mam nadzieję, że nie będzie to zbyt wiele wstecznego śledzenia.
Edycja: Kontrprzykład Mysticial poniżej pokazuje, że w rzeczywistości nie jest to gwarantowane optymalne, niezależnie od powiązań wagowych. W niektórych przypadkach zmniejszenie ciężaru tak bardzo, jak to możliwe na danym etapie, faktycznie pozostawia pozostałe bomby zbyt rozłożone, aby osiągnąć tak wysokie skumulowane zmniejszenie po drugim etapie, jak można to zrobić przy nieco mniej chciwym wyborze w pierwszym kroku. Byłem nieco wprowadzony w błąd przez pogląd, że wyniki są niewrażliwe na kolejność bombardowań. one sąniewrażliwy na kolejność, ponieważ możesz wziąć dowolną serię bombardowań i odtworzyć je od początku w innej kolejności, aby uzyskać tę samą wynikową planszę. Ale nie wynika z tego, że możesz rozważyć każde bombardowanie niezależnie. Lub przynajmniej każde bombardowanie musi być rozpatrywane w sposób uwzględniający to, jak dobrze układa planszę do kolejnych bombardowań.
źródło
1010101
,0010100
może być kontrprzykładem, który dowodzi, że takie podejście nie jest optymalne. To podejście wymaga 3. Można tego dokonać w 2.Załóżmy, że policzymy pozycje planszy 1, 2, ..., nx m. Każda sekwencja zrzutów bomb może być reprezentowana przez sekwencję liczb w tym zestawie, gdzie liczby mogą się powtarzać. Jednak efekt na planszy jest taki sam, niezależnie od kolejności zrzucania bomb, więc tak naprawdę każdy wybór zrzutów bomb może być reprezentowany jako lista liczb NXM, gdzie pierwsza liczba reprezentuje liczbę bomb zrzuconych na pozycję 1 , druga liczba reprezentuje liczbę bomb zrzuconych na pozycję 2 itd. Nazwijmy tę listę liczb nxm „kluczem”.
Możesz najpierw spróbować obliczyć wszystkie stany planszy wynikające z 1 zrzutu bomby, a następnie użyć ich do obliczenia wszystkich stanów planszy wynikających z 2 zrzutów bomby itp., Aż do uzyskania wszystkich zer. Ale na każdym kroku buforowałbyś stany za pomocą klucza, który zdefiniowałem powyżej, więc możesz wykorzystać te wyniki przy obliczaniu następnego kroku (podejście „programowania dynamicznego”).
Ale w zależności od wielkości n, m oraz liczb w siatce wymagania pamięciowe tego podejścia mogą być nadmierne. Możesz wyrzucić wszystkie wyniki dla N bombardowania po obliczeniu wszystkich wyników dla N + 1, więc są pewne oszczędności. I oczywiście nie można cache'ować niczego kosztem dużo dłużej - podejście programowania dynamicznego handluje pamięci dla prędkości.
źródło
Jeśli chcesz, aby absolutnie optymalne rozwiązanie oczyściło płytę, będziesz musiał użyć klasycznego backtracka, ale jeśli matryca jest bardzo duża, znalezienie najlepszego rozwiązania zajmie wieki, jeśli chcesz „możliwego” optymalnego rozwiązania, możesz użyć chciwego algorytmu , jeśli potrzebujesz pomocy w napisaniu algorytmu, mogę Ci pomóc
Pomyśl, że to najlepszy sposób. Zrób kolejną macierz, w której przechowujesz punkty, które usuwasz, zrzucając tam bombę, a następnie wybierz komórkę z maksymalną liczbą punktów i upuść bombę tam zaktualizuj macierz punktów i kontynuuj. Przykład:
wartość komórki +1 dla każdej sąsiedniej komórki o wartości większej niż 0
źródło
Brutalna siła !
Wiem, że to nie jest wydajne, ale nawet jeśli znajdziesz szybszy algorytm, zawsze możesz przetestować ten wynik, aby sprawdzić jego dokładność.
Użyj rekurencji, takiej jak ta:
Możesz uczynić to bardziej wydajnym przez buforowanie, jeśli inny sposób prowadzi do tego samego wyniku, nie powinieneś powtarzać tych samych kroków.
Opracować:
jeśli bombardowanie komórki 1,3,5 prowadzi do tego samego wyniku co bombardowanie komórki 5,3,1, to nie powinieneś ponownie wykonywać wszystkich kolejnych kroków w obu przypadkach, wystarczy tylko 1, powinieneś gdzieś przechowywać wszystko stany tabeli i użyj ich wyników.
Do szybkiego porównania można użyć skrótu statystyk tabeli.
źródło
Edycja: nie zauważyłem, że Kostek zasugerował prawie takie samo podejście, więc teraz mocniej twierdzę: jeśli narożniki do usunięcia są wybierane tak, aby zawsze znajdowały się na najbardziej zewnętrznej warstwie, jest to optymalne.
W przykładzie OP: upuszczenie 2 (jako 1 + 1 lub 2) na czymkolwiek innym niż na 5 nie prowadzi do trafienia w pole, które trafiłoby na 5. Więc musimy po prostu upuścić 2 na 5 (i 6 w lewym dolnym rogu 1 ...)
Po tym jest tylko jeden sposób, aby wyczyścić (w lewym górnym rogu) to, co pierwotnie było 1 (teraz 0), a mianowicie poprzez upuszczenie 0 na B3 (cel jak notacja). I tak dalej.
Dopiero po wyczyszczeniu całych kolumn A i E oraz 1 i 7 wierszy rozpocznij czyszczenie jednej warstwy głębiej.
Rozważ wyczyszczenie tylko tych celowo wyczyszczonych, wyczyszczenie rogów wartości 0 nic nie kosztuje i upraszcza myślenie o tym.
Ponieważ wszystkie bomby zrzucone w ten sposób muszą zostać zrzucone, a to prowadzi do wyczyszczonych pól, jest to optymalne rozwiązanie.
Po dobrym śnie uświadomiłem sobie, że to nieprawda. Rozważać
Moje podejście zrzuciłoby bomby na B3 i C2, gdy wystarczyło by zrzucić na B2
źródło
Oto moje rozwiązanie .. Nie wypiszę go jeszcze w kodzie, ponieważ nie mam czasu, ale uważam, że powinno to przynieść optymalną liczbę ruchów za każdym razem - choć nie jestem pewien, jak efektywne byłoby znalezienie punkty do bombardowania.
Po pierwsze, jak stwierdził @Luka Rahne w jednym z komentarzy, kolejność bombardowania nie jest ważna - tylko kombinacja.
Po drugie, jak wielu innych stwierdziło, bombardowanie 1-przekątnej z rogów jest optymalne, ponieważ dotyka większej liczby punktów niż narożników.
To generuje podstawę dla mojej wersji algorytmu: możemy zbombardować „1-off od narożników” pierwszy lub ostatni, to nie ma znaczenia (teoretycznie) Bombardujemy je jako pierwsze, ponieważ ułatwia to późniejsze decyzje (w praktyce) Bombardujemy punkt, który wpływa na najwięcej punktów, jednocześnie bombardując te rogi.
Zdefiniujmy Punkty Oporu, aby były to punkty na planszy z największą liczbą punktów niepodlegających bombardowaniu + największą liczbą zer wokół nich
punkty niepodlegające bombardowaniu można zdefiniować jako punkty, które nie istnieją w naszym obecnym zakresie planszy, na którą patrzymy.
Zdefiniuję również 4 granice, które będą obsługiwać nasz zakres: Góra = 0, Lewo = 0, Dół = k, Prawo = j. (wartości na początek)
Na koniec zdefiniuję optymalne bomby jako bomby zrzucane na punkty przylegające do punktów oporu i dotykające (1) punktu oporu o najwyższej wartości i (2) największej możliwej liczby punktów.
Jeśli chodzi o podejście - to oczywiste, że pracujemy z zewnątrz. Będziemy mogli pracować z 4 bombowcami jednocześnie.
Pierwsze punkty oporu to oczywiście nasze rogi. Punkty „poza granicami” nie są bombardowane (dla każdego rogu jest 5 punktów poza zakresem). Najpierw bombardujemy punkty po przekątnej jeden za rogiem.
Algorytm:
powtarzaj, aż GÓRA = DÓŁ i LEWO = PRAWO
Spróbuję później napisać właściwy kod
źródło
Możesz użyć planowania przestrzeni stanu. Na przykład użycie A * (lub jednego z jego wariantów) w połączeniu z taką heurystyką
f = g + h
:źródło
Mam także 28 ruchów. Użyłem dwóch testów dla najlepszego następnego ruchu: pierwszy ruch dający minimalną sumę dla planszy. Po drugie, dla równych kwot ruch dający maksymalną gęstość, zdefiniowany jako:
To jest Haskell. „tablica rozwiązywania” pokazuje rozwiązanie silnika. Możesz zagrać w grę, wpisując „główny”, a następnie wprowadź punkt docelowy, „najlepszy”, aby uzyskać rekomendację, lub „wyjdź”, aby wyjść.
WYJŚCIE:
* Główna> rozwiąż planszę
[(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)]
źródło
Wydaje się, że istnieje tutaj niepasująca do dwóch stron podstruktura. Rozważ następujące wystąpienie:
Optymalne rozwiązanie tego przypadku ma rozmiar 5, ponieważ jest to rozmiar minimalnego pokrycia wierzchołków 9-cyklowego brzegu.
W szczególności ten przypadek pokazuje, że relaksacja programowania liniowego, którą opublikowało kilka osób, nie jest dokładna, nie działa i wszystkie inne złe rzeczy. Jestem prawie pewien, że mogę zredukować „pokrycie wierzchołków mojego płaskiego wykresu sześciennego o jak najmniejszą liczbę krawędzi” do twojego problemu, co sprawia, że wątpię, czy którekolwiek z zachłannych / wspinaczkowych rozwiązań będzie skuteczne.
W najgorszym przypadku nie widzę sposobu na rozwiązanie tego problemu w czasie wielomianowym. Może być bardzo sprytne rozwiązanie do wyszukiwania binarnego i DP, którego nie widzę.
EDYCJA : Widzę, że konkurs ( http://deadline24.pl ) jest niezależny od języka; wysyłają ci kilka plików wejściowych, a ty wysyłasz im dane wyjściowe. Więc nie potrzebujesz czegoś, co działa w najgorszym przypadku wielomianu. W szczególności możesz spojrzeć na dane wejściowe !
Na wejściu znajduje się kilka małych skrzynek. Potem jest obudowa 10 x 1000, obudowa 100 x 100 i obudowa 1000 x 1000. Wszystkie trzy duże przypadki są bardzo dobrze wychowane. Pozycje sąsiadujące poziomo mają zazwyczaj tę samą wartość. Na stosunkowo mocnej maszynie jestem w stanie rozwiązać wszystkie przypadki, brutalnie zmuszając CPLEX w zaledwie kilka minut. Mam szczęście na 1000x1000; relaksacja LP ma zintegrowane optymalne rozwiązanie. Moje rozwiązania są zgodne z
.ans
plikami zawartymi w pakiecie danych testowych.Założę się, że możesz użyć struktury danych wejściowych w znacznie bardziej bezpośredni sposób niż ja, jeśli na to spojrzysz; wygląda na to, że możesz po prostu wytrząsnąć pierwszy rząd lub dwa lub trzy razy, aż nie pozostanie nic. (Wygląda na to, że w 1000 x 1000 wszystkie wiersze nie rosną? Chyba stąd pochodzi Twoja „część B”?)
źródło
Nie mogę wymyślić sposobu na obliczenie rzeczywistej liczby bez obliczenia kampanii bombardowania przy użyciu mojej najlepszej heurystyki i mam nadzieję, że uzyskam rozsądny wynik.
Więc moją metodą jest obliczenie wskaźnika wydajności bombardowania dla każdej komórki, zbombardowanie komórki o największej wartości, ... iteracja procesu, aż wszystko spłaszczę. Niektórzy opowiadają się za stosowaniem jako miernika prostej potencjalnej szkody (tj. Oceny od 0 do 9), ale nie wystarcza to, gdy uderzają komórki o wysokiej wartości i nie wykorzystują nakładających się uszkodzeń. Obliczę
cell value - sum of all neighbouring cells
, zresetuję każdy dodatni na 0 i użyję wartości bezwzględnej dowolnego ujemnego. Intuicyjnie ta metryka powinna dokonać wyboru, który pomoże zmaksymalizować nakładanie się obrażeń na komórki o dużej liczbie, zamiast bezpośredniego ich walenia.Poniższy kod osiąga całkowite zniszczenie pola testowego w 28 bombach (zauważ, że użycie potencjalnego uszkodzenia jako miary daje 31!).
Wynikowy wzorzec bombardowania jest wyprowadzany w następujący sposób (wartości pola po lewej stronie, dane po prawej)
źródło
Można to rozwiązać za pomocą drzewa o głębokości O (3 ^ (n)). Gdzie n jest sumą wszystkich kwadratów.
Najpierw rozważ, że rozwiązanie problemu z drzewem O (9 ^ n) jest banalne, po prostu weź pod uwagę wszystkie możliwe lokalizacje bombardowań. Na przykład zobacz implementację Alfe .
Następnie zdaj sobie sprawę, że możemy pracować, aby bombardować od podstaw i nadal uzyskać minimalny wzór bombardowania.
Ten algorytm jest poprawny, ponieważ
W praktyce algorytm ten będzie regularnie działał lepiej niż teoretyczne maksimum, ponieważ regularnie bombarduje sąsiadów i zmniejsza rozmiar wyszukiwania. Jeśli założymy, że każde bombardowanie zmniejsza wartość 4 dodatkowych celów, wówczas nasz algorytm będzie działał w O (3 ^ (n / 4)) lub w przybliżeniu O (1,3 ^ n).
Ponieważ ten algorytm jest wciąż wykładniczy, rozsądnie byłoby ograniczyć głębokość wyszukiwania. Możemy ograniczyć liczbę rozgałęzień do pewnej liczby, X, a gdy jesteśmy już tak głęboko, zmuszamy algorytm do wyboru najlepszej ścieżki, którą do tej pory zidentyfikował (tej, która ma minimalną całkowitą sumę płyty w jednym ze swoich listek końcowych ). W takim przypadku nasz algorytm będzie działał w czasie O (3 ^ X), ale nie ma gwarancji uzyskania poprawnej odpowiedzi. Zawsze możemy jednak zwiększyć X i przetestować empirycznie, czy warto skorzystać z kompromisu między zwiększonym obliczeniem a lepszymi odpowiedziami.
źródło
funkcja oceny, suma całkowita:
funkcja celu:
funkcja zniszczenia:
funkcja celu:
funkcja maksymalizacji liniowej:
Nie jest to optymalne, ale można je zoptymalizować poprzez znalezienie lepszej funkcji oceny.
.. ale myśląc o tym problemie, myślałem, że jednym z głównych problemów jest w pewnym momencie porzucenie liczb na środku zer, więc przyjmuję inne podejście .. którym jest dominacja minimalnych wartości do zera, a następnie spróbuj zera zerowe, jak to możliwe, co prowadzi do ogólnej minimalizacji minimalnych istniejących wartości lub podobnych
źródło
Cały ten problem sprowadza się do obliczenia odległości edycji. Wystarczy obliczyć wariant odległości Levenshteina między daną macierzą a macierzą zerową, w której zmiany są zastępowane bombardowaniem, za pomocą programowania dynamicznego do przechowywania odległości między macierzami pośrednimi. Sugeruję użycie skrótu macierzy jako klucza. W pseudo-Python:
źródło
To była odpowiedź na pierwsze zadane pytanie. Nie zauważyłem, że zmienił parametry.
Utwórz listę wszystkich celów. Przypisz wartość do celu na podstawie liczby dodatnich wartości, na które ma wpływ upuszczenie (sam i wszyscy sąsiedzi). Najwyższą wartością byłoby dziewięć.
Sortuj cele według liczby trafionych celów (Malejąco), z dodatkowym sortowaniem malejącym według sumy każdego trafionego celu.
Zrzuć bombę na najwyżej sklasyfikowany cel, a następnie ponownie oblicz cele i powtarzaj, aż wszystkie wartości będą równe zero.
Uzgodnione, nie zawsze jest to najbardziej optymalne. Na przykład,
Takie podejście wymagałoby usunięcia 5 bomb. Optymalnie jednak można to zrobić w 4. Nadal dość cholernie blisko i nie ma cofania się. W większości sytuacji będzie optymalna lub bardzo bliska.
Wykorzystując oryginalne numery problemów, podejście to rozwiązuje 28 bomb.
Dodanie kodu w celu zademonstrowania tego podejścia (za pomocą formularza z przyciskiem):
Klasa, której będziesz potrzebować:
źródło
09090
To podejście wymaga 18 bomb. Można to zrobić w 9.1010101
,0010100
?