Przeskocz do treści

Delta mi!

Prostokąt arytmetyczny

Jakub Radoszewski

o artykule ...

  • Publikacja w Delcie: marzec 2012
  • Publikacja elektroniczna: 02-03-2012

W tym artykule omówimy zadanie Prostokąt arytmetyczny z Akademickich Mistrzostw Polski w Programowaniu Zespołowym 2011.

Jednak zanim to zrobimy, zastanowimy się nad dwoma pozornie niezwiązanymi problemami.

obrazek

Rys. 1

Rys. 1

Problem 1. Dany jest math-elementowy ciąg liczb całkowitych math Chcielibyśmy dla każdego elementu ciągu wyznaczyć najbliższy mniejszy od niego element położony na lewo od niego. Formalnie, dla każdego math szukamy największego takiego math  math że math Aby ta wartość była zawsze zdefiniowana, dokładamy sztuczny element math  (patrz Rys. 1).

Najprostszy algorytm rozwiązujący Problem 1 działa w czasie math  Używając sprytnych struktur danych (zrównoważone drzewa binarne), można otrzymać rozwiązanie działające w czasie math  Podany problem można jednak rozwiązać prosto i liniowo, jeśli tylko pójdzie się za strzałkami.

obrazek

Rys. 2

Rys. 2

Idea takiego rozwiązania jest jasna: będziemy przypisywać strzałki kolejnym elementom, od lewej do prawej. Dla danego math zaczynamy od sprawdzenia, czy math Jeśli tak, to wiemy, że strzałka z math prowadzi do math A jeśli nie, to idziemy do pierwszego elementu mniejszego niż math czyli dokładnie wzdłuż strzałki z math Kontynuujemy to postępowanie aż do momentu, gdy znajdziemy element mniejszy niż math Przykładowo, rysunek 2 ilustruje wyznaczanie strzałki wychodzącej z trójki.

obrazek

Rys. 3

Rys. 3

obrazek

Rys. 4

Rys. 4

Aby uzasadnić, że ten algorytm jest liniowy, wystarczy pokazać, że wzdłuż każdej strzałki przejdziemy co najwyżej raz. Faktycznie, jeśli przy wyznaczaniu strzałki dla math przechodzimy wzdłuż strzałki wychodzącej z pewnego math ( math), to wiemy, że math To oznacza, że każda strzałka wychodząca z elementów math prowadzi albo do math lub elementu położonego na prawo od math albo do jakiegoś elementu mniejszego niż math a zatem położonego na lewo od math Strzałkę wychodzącą z math wykorzystamy zatem dokładnie raz, co chcieliśmy wykazać.

Problem 2. Mamy daną tablicę rozmiaru math wypełnioną zerami i jedynkami. Należy znaleźć prostokątny fragment tej tablicy wypełniony samymi jedynkami o jak największej powierzchni (patrz Rys. 3).

Ten problem pojawił się na IX Olimpiadzie Informatycznej jako zadanie Działka.

Wszystkich prostokątów w takiej tablicy jest rzędu math więc problem trzeba rozwiązywać jakoś sprytniej. Znana jest cała gama rozwiązań o złożoności czasowej math   math  a nawet math  Pokażemy tu dosyć proste rozwiązanie o optymalnej złożoności math  Zacznijmy od wyznaczenia dla każdego pola math tablicy liczby kolejnych pól wypełnionych jedynkami położonych w dół od tego pola, wliczając samo pole math Oznaczmy tę wartość przez math  Takie wartości łatwo wyznaczamy w czasie math  idąc od dołu do góry tablicy (Rys. 4). Zauważmy, że math jest niezerowe tylko wtedy, gdy oryginalna tablica w polu math miała jedynkę.

Teraz przychodzi kluczowe spostrzeżenie. Otóż poszukiwany prostokąt możemy skonstruować tak: bierzemy jakieś pole math i wyznaczamy prostokąt zawierający to pole w górnym wierszu, o wysokości math  i sięgający w prawo i w lewo tak daleko, jak tylko się da. Faktycznie, wynikowy prostokąt nie może być rozszerzony w dół (ani w żadną inną stronę), więc musi być opisanej postaci dla pewnego pola math Przykładowo, na rysunkach 3 i 4 pole math wynikowego prostokąta (kwadratu) o powierzchni 9 to jego prawy górny róg.

Dla każdego pola math o niezerowym math  szukamy zatem najbliższych pól w tym samym wierszu, dla których wartości math  są mniejsze niż math  czyli takich indeksów math  że math  math  jest maksymalne, a math – minimalne. Wówczas wynikiem jest maksimum z iloczynów postaci math dla wszystkich pól math  Zauważmy jednak, że jest to dokładnie zastosowanie Problemu 1 do math-tego wiersza tablicy math  tyle że raz od lewej do prawej (wyznaczanie math ), a raz od prawej do lewej (wyznaczanie math ). Wystarczy otoczyć tablicę math obwódką z polami zawierającymi math  i możemy już zastosować poprzedni algorytm, wiersz po wierszu. Dostajemy żądany czas math

obrazek

Rys. 5

Rys. 5

Przyszła wreszcie pora, aby sformułować wspomniane na wstępie zadanie o prostokącie arytmetycznym.

Problem 3. Znów mamy daną tablicę rozmiaru math tym razem mogą się w niej znajdować dowolne nieujemne liczby całkowite. Szukamy w niej prostokąta arytmetycznego o maksymalnej powierzchni, przy czym prostokąt arytmetyczny to prostokąt, w którym liczby w każdym wierszu oraz w każdej kolumnie tworzą ciąg arytmetyczny (patrz Rys. 5).

Na początek zajmijmy się prostokątami o wysokości 1. Widzimy, że każdy wiersz tablicy możemy podzielić na maksymalne ciągi arytmetyczne, z których każdy ma długość co najmniej dwa i każde dwa kolejne ciągi mają dokładnie jeden element wspólny. Przykładowo, dolny wiersz tablicy z rysunku 5 dzielimy na ciągi math i math a górny na ciągi math i math Korzystając z takiego przedstawienia, w czasie math  łatwo znajdziemy najdłuższy prostokąt arytmetyczny o wysokości 1. Podobnie rozpatrujemy prostokąty o długości 1, wysokości 2 (jak?) i długości 2.

obrazek

Rys. 6

Rys. 6

Odtąd interesować nas będą tylko prostokąty, których każdy bok ma długość co najmniej 3. Znajdowanie takich prostokątów sprowadzimy do zadania Działka.

Zaznaczmy mianowicie kółkiem każdy taki element tablicy, że kwadrat o boku 3 zawierający ten element w środku jest prostokątem arytmetycznym (Rys. 6). Okazuje się, że prostokąt o obu wymiarach nie mniejszych niż 3 jest arytmetyczny wtedy i tylko wtedy, gdy wszystkie zawarte w nim elementy tablicy (poza, ewentualnie, jego wewnętrzną obwódką o szerokości 1) są zaznaczone kółkami. Rzeczywiście, jeśli prostokąt jest arytmetyczny, to każdy jego podprostokąt jest arytmetyczny, więc w szczególności wszystkie kwadraty o boku 3, zawarte w tym prostokącie, są arytmetyczne. A w drugą stronę, jeśli mamy dwa sąsiednie elementy tablicy zaznaczone kółkami, to ciągi arytmetyczne w otaczających je kwadratach math sklejają się w dłuższe ciągi arytmetyczne dokładnie tak, jak trzeba.

obrazek

Podsumowując

Wąskie prostokąty arytmetyczne rozpatrzyliśmy osobno, a problem szukania odpowiednio grubego prostokąta arytmetycznego o maksymalnej powierzchni sprowadziliśmy do poszukiwania maksymalnych prostokątów złożonych wyłącznie z wyróżnionych pól, czyli dokładnie do Problemu 2. Całe rozwiązanie działa w optymalnym czasie math  i jest, w sumie, całkiem sprytne.

Na koniec ciekawa własność prostokątów arytmetycznych, która może zainteresować także nieinformatyków: prostokąt o wysokości co najmniej 2 jest arytmetyczny wtedy i tylko wtedy, gdy liczby w każdej jego kolumnie oraz w dowolnych dwóch jego wierszach tworzą ciągi arytmetyczne. Dodajmy, że ta własność nie zachodzi, jeśli wymagamy tylko, aby jeden wiersz prostokąta stanowił ciąg arytmetyczny.