Informatyczny kącik olimpijski
Myszy
Tym razem zajmiemy się zadaniem, które pojawiło się na kolokwium dla studentów pierwszego roku informatyki na Uniwersytecie Warszawskim.

Dla oraz tablicy

poprawnym wynikiem jest 14. Jeden kot może pilnować fragmentu korytarza na metrach od 2 do 4 (łapiąc 6 z 10 myszy), a drugi może pilnować fragmentu na metrach od 5 do 7 (łapiąc 8 z 12 myszy).
W korytarzu harcują myszy. Korytarz ma długość metrów. Dana jest tablica
nieujemnych liczb całkowitych
opisująca, gdzie jest ile myszy: dla
na
-tym metrze korytarza (patrząc od strony wejścia) jest
myszy. Dysponujesz
kotami
Twoim zadaniem jest takie rozmieszczenie kotów w korytarzu, żeby złapały jak najwięcej myszy. Każdy kot może pilnować ustalonego przez Ciebie spójnego fragmentu korytarza (na przykład, może mieć założoną smycz odpowiedniej długości, przymocowaną do podłogi pośrodku pilnowanego fragmentu korytarza). Fragmenty korytarza pilnowane przez różne koty nie mogą zachodzić na siebie (żeby koty się nie pobiły, a smycze nie poplątały), choć mogą się stykać. Niektóre fragmenty korytarza mogą pozostać niepilnowane przez żadnego kota. Kot, który pilnuje fragmentu od
-tego do
-tego metra włącznie (dla
), na którym znajduje się
myszy, złapie:
myszy. Należy wyznaczyć maksymalną liczbę myszy, jakie mogą złapać koty (patrz rysunek).
Obojętnie, jak zabierzemy się za to zadanie, przyda się nam tablica sum prefiksowych: Wtedy liczba myszy na fragmencie
przedstawia się jako
Omawiane zadanie to zadanie na programowanie dynamiczne. Niech oznacza maksymalną liczbę myszy, jakie może złapać
kotów na pierwszych
metrach korytarza. Ponieważ niektóre fragmenty mogą być niepilnowane, więc rekurencję budujemy, rozpatrując dwa przypadki: albo
-ty metr nie jest pilnowany, albo jest i
-ty kot pilnuje fragmentu
(od
-tego do
-tego metra włącznie):
![]() |
(*) |
Podstawowa implementacja zadziała w czasie Takie było oczekiwane rozwiązanie na kolokwium, niemniej jednak okazało się, że można to zrobić lepiej (ach, ci studenci). Aby przyspieszyć rozwiązanie, należy w odpowiedniej kolejności wypełniać tablicę
Główna pętla powinna przebiegać po
Ustalmy
i załóżmy, że mamy obliczone wartości
dla wszystkich
Będziemy teraz obliczać element
Kluczem do usprawnienia rozwiązania jest porównanie możliwych dwóch ustawień
-tego kota, mianowicie gdy patroluje on fragment
lub fragment
gdzie
Drugie ustawienie jest lepsze od pierwszego, jeśli:
![]() |
Po przekształceniu nierówność przyjmie postać:
![]() |
(**) |
Prawa strona nierówności zależy tylko od
i
(oraz od
); oznaczmy ją przez
Widzimy, że pierwsze ustawienie jest lepsze dla
mniejszych od
po czym, począwszy od
lepsze staje się drugie ustawienie. Ta obserwacja umożliwia przeglądanie możliwych ustawień
-tego kota w sposób bardziej uporządkowany tak, że na bieżąco eliminujemy takie ustawienia, które są już od pewnych
gorsze. Trzymamy kolejkę dwukierunkową początków fragmentów
taką że
![]() |
Innymi słowy, dla odpowiednio małych najlepiej przydzielać
-temu kotu fragment
gdy
osiągnie
- fragment
i tak dalej aż do
gdzie optymalny przydział to
Przetwarzanie
-tego metra korytarza składa się z następujących kroków:
- 1.
- Jeżeli kolejka ma co najmniej dwa elementy oraz
to usuwamy z przodu kolejki
gdyż od tego momentu lepsze będą fragmenty o początku
- 2.
- Jeżeli kolejka ma wciąż co najmniej dwa elementy, to sprawdzamy, czy
Jeżeli tak, to fragmenty o początku
są zdominowane przez fragmenty o początkach
lub
usuwamy więc
z końca kolejki i powtarzamy krok 2.
- 3.
- Dodajemy
na koniec kolejki.
- 4.
- Obliczamy
korzystając ze wzoru
ale możemy to już teraz zrobić w czasie
gdyż wiemy, że maksimum jest osiągane przy
gdzie
jest aktualnym elementem z przodu kolejki.
W ten sposób otrzymaliśmy rozwiązanie o złożoności czasowej