Przeskocz do treści

Delta mi!

Informatyczny kącik olimpijski

Teleporty

Jakub Radoszewski

o artykule ...

  • Publikacja w Delcie: grudzień 2012
  • Publikacja elektroniczna: 30-11-2012
  • Wersja do druku [application/pdf]: (42 KB)

W tej edycji kącika omówimy zadanie pt. Podlewanie ogórków (naprawdę!) z rundy 2A konkursu TopCoder Open 2012.

W zadaniu dany jest pewien zbiór punktów ustawionych wzdłuż prostej i naszym celem jest odwiedzić wszystkie te punkty w pewnej zadanej kolejności. Innymi słowy, mamy math różnych punktów ponumerowanych od math do math (porządek numerów niekoniecznie od lewej do prawej) i powinniśmy odwiedzić je wszystkie w kolejności math Pomóc nam w tym mogą teleporty – mamy możliwość rozstawić w dowolnych punktach prostej łącznie math teleportów. Teleporty działają tak, że w ułamku sekundy możemy teleportować się z dowolnego teleportu do dowolnego innego teleportu. Naszym zadaniem jest tak ustawić dostępne teleporty, aby zminimalizować długość trasy odwiedzającej po kolei punkty math przy założeniu, że po drodze możemy teleportować się dowolnie wiele razy.

Rozwiązywanie każdego (nietrywialnego) zadania warto rozpocząć od wstępnej analizy problemu, czyli od stwierdzenia, o co w nim tak naprawdę chodzi. Niech math oznaczają współrzędne kolejnych punktów od lewej do prawej, a math – numery tych punktów. Niech wreszcie math oznaczają współrzędne punktów w porządku zadanych numerów math Zauważmy, że poszukiwaną optymalną ścieżkę możemy podzielić na fragmenty: od math do math od math do math itd., przy czym każdy z fragmentów biegnie albo w linii prostej między punktami math a  math albo ścieżką od punktu math do najbliższego mu teleportu i od teleportu najbliższego punktowi math do punktu math

Na pewno warto coś zrobić z faktem, że zgodnie z treścią zadania liczba możliwych rozstawień teleportów jest nieskończona. Naturalna hipoteza jest taka, że możemy ograniczyć się do teleportów ustawionych w pewnych spośród zadanych math punktów. Łatwo uzasadnić prawdziwość tej hipotezy: Załóżmy, że pewien teleport znajdowałby się gdzieś pomiędzy dwoma sąsiednimi punktami, czyli na pozycji math takiej że math dla pewnego math Rozważmy wszystkie momenty, w których korzystamy z teleportu math W każdym z nich musimy dojść do tego teleportu albo od punktu math (bądź innego, położonego na lewo), albo od punktu math (bądź innego, położonego na prawo). To oznacza, że odcinek math przejdziemy math razy, a odcinek math przejdziemy math razy. Jeśli więc math to teleport przestawiamy na pozycję math a w przeciwnym razie na pozycję math i w obu przypadkach długość trasy nam nie wzrośnie.

Mamy już jakąś wizję tego, jak będzie wyglądała optymalna trasa oraz gdzie powinniśmy ustawiać teleporty. To pozwala już skonstruować pierwsze rozwiązanie zadania, rozpatrujące wszystkie możliwe rozstawienia teleportów. Złożoność czasowa takiego rozwiązania to z grubsza math

Aby poprawić ten rezultat, powinniśmy jakoś „dobrze uchwycić” nasze zadanie. Problem ewidentnie stanowi w nim obecność dwóch porządków: zadanego porządku odwiedzania punktów oraz naturalnej kolejności „od lewej do prawej”, odpowiadającej najkrótszym ścieżkom między kolejnymi punktami. Potrzebujemy jeszcze jakichś spostrzeżeń.

Załóżmy, że znamy pozycje wszystkich rozstawionych teleportów: math Teleporty te wyznaczałyby wówczas podział ciągu wszystkich punktów na fragmenty położone między kolejnymi teleportami. Czy na podstawie tego podziału umielibyśmy łatwo obliczyć wynik?

Rozważmy pewien punkt math taki że math  Oznaczmy math Wiemy, że poprzedni punkt w kolejności odwiedzania znajduje się na pozycji math (punkt ten może też nie istnieć). Jeśli teraz punkt math szczęśliwym trafem również znajduje się między teleportami math i  math to możemy bardzo łatwo wyznaczyć najkrótszą ścieżkę między nim a  math: albo idziemy bezpośrednio po prostej, albo korzystamy z kombinacji teleportów math i  math A co, jeśli punkt math znajduje się zupełnie gdzieś indziej? Wiemy wówczas, że najkrótsza ścieżka od math do math biegnie od math do najbliższego mu teleportu i dalej od teleportu najbliższego math do math (zauważmy, że jeśli wynikiem jest najkrótsza ścieżka z  math do math w linii prostej, to i tak możemy ją opisać w podanej postaci!). To oznacza, że wkład punktu math do wyniku możemy opisać całkiem lokalnie: jeśli mianowicie math to do wyniku dodajemy

display-math(1)

a w przeciwnym razie wynik zwiększamy tylko o

display-math(2)

natomiast odległość od punktu math do najbliższego mu teleportu dodamy do wyniku w chwili rozpatrywania tego punktu. Aby ta metoda była poprawna, przy rozpatrywaniu math należy jeszcze stwierdzić, czy następny punkt w kolejności odwiedzania, math znajduje się między teleportami math i  math a jeśli nie, jeszcze raz dodać do wyniku składnik (2). (Jeśli math nie istnieje, nie musimy niczego dodawać).

To oznacza, że do wyznaczenia wyniku wystarcza nam dla każdego punktu znajomość pozycji dwóch najbliższych mu teleportów. Możemy więc zastosować metodę programowania dynamicznego. W ramach stanu musimy na pewno jakoś zapamiętać zakres rozpatrzonych punktów wzdłuż prostej, liczbę już ustawionych teleportów oraz pozycje skrajnych ustawionych teleportów. Najlepiej jest to zrobić tak: pole math tablicy będzie odpowiadać minimalnej sumie wkładów punktów math do wyniku, przy założeniu, że rozstawiliśmy wśród nich math teleportów, z których ostatni znajduje się na pozycji math Wówczas ze stanu math  mamy math  przejść, do stanów postaci math  dla math  i możemy je wszystkie rozpatrzyć w czasie math  Żeby uniknąć nieprzyjemnych przypadków brzegowych, postawimy łącznie math teleporty, z czego dwa pomocnicze: jeden na pozycji math a drugi na pozycji math

Całe rozwiązanie działa w czasie math  i pamięci math