Informatyczny kącik olimpijski
Jeszcze dwa zadania do plecaka
W kąciku kontynuujemy przygodę z zadaniami, do których rozwiązania przydaje się znajomość problemu plecakowego. Tym razem w nieco trudniejszej jego wersji, w której każdy przedmiot ma swój rozmiar oraz wartość
Standardowe pytanie, które możemy wtedy zadać, to np. jaka jest największa sumaryczna wartość przedmiotów, które możemy zapakować do plecaka, nie przekraczając jego udźwigu
Zacznijmy od zadania Meble z Obozu Naukowo-Treningowego im. A. Kreczmara z roku 2013. Chcemy urządzić mieszkanie i w tym celu zakupiliśmy rodzajów mebli do samodzielnego montażu. Mamy
sztuk mebla rodzaju
; złożenie pierwszej sztuki tego rodzaju zajmie nam
minut, a wraz z postępem prac będziemy nabierać wprawy i złożenie kolejnej sztuki zajmie nam o
minut krócej niż poprzedniej (zakładamy, że
). Chcemy wiedzieć, ile minimalnie czasu potrzebujemy, aby złożyć dowolnych
mebli.
Naturalne jest tu zastosowanie programowania dynamicznego. Jeśli oznaczymy przez minimalny czas złożenia
mebli, gdy rozważamy jedynie rodzaje od 1 do
to odpowiedzią będzie
a rekurencją do niej prowadzącą wzór:
![]() |
gdzie jest czasem montażu
mebli rodzaju
To rozwiązanie działa w czasie
Intuicyjnie rzecz biorąc, jeśli już zaczęliśmy składać meble danego rodzaju, to opłaca się nam wykorzystać zdobyte doświadczenie do maksimum. A formalnie: istnieje optymalne rozwiązanie, w którym mamy co najwyżej jeden rodzaj mebla którego złożymy więcej niż 0, ale mniej niż
sztuk. Istotnie, załóżmy, że mamy co najmniej dwa takie nietrywialne rodzaje
i
których składamy odpowiednio
i
sztuk. Jeśli ostatni mebel rodzaju
składamy nie dłużej niż ostatni mebel rodzaju
to składając dodatkowe
sztuk rodzaju
zamiast
sztuk rodzaju
nie pogorszymy czasu, a zmniejszymy liczbę nietrywialnych rodzajów mebli.
Rozważmy zatem wszystkie możliwości wyboru nietrywialnego mebla Dla ustalonego
pogrupujmy pozostałe rodzaje mebli
w paczki o rozmiarach
i czasach montażu
i rozwiążmy dla nich problem plecakowy, w którym pytamy się o najmniejszą wartość przedmiotów całkowicie wypełniających plecak o udźwigu
Dzięki temu w czasie
dostaniemy tablicę
w której
oznaczać będzie minimalny czas potrzebny na złożenie dokładnie
mebli, jeśli pochodzić będą z pewnej liczby w całości złożonych paczek. Zatem, dokładając do tego
sztuk mebla
(dla wszystkich wartości
), zmontujemy
mebli w czasie
Złożoność czasowa tego rozwiązania to
Zauważmy, że główny koszt algorytmu to rozwiązanie problemu plecakowego dla każdego podzbioru przedmiotów. Używając techniki, o której pisaliśmy w zeszłym miesiącu, możemy zmniejszyć złożoność czasową do
Drugie zadanie pochodzi z Wiosennego Turnieju w Programowaniu Zespołowym organizowanego przez Politechnikę Poznańską (a konkretnie z 8. edycji z roku 2004) i ma tytuł (kto by się spodziewał) Pakowanie plecaka. W zadaniu mamy plecak o udźwigu i
przedmiotów, z których każdy ma swój rozmiar
oraz użyteczność
(przy czym niektóre przedmioty mogą być wyjątkowo nieprzydatne i mieć ujemną użyteczność). Chcemy znaleźć maksymalne upakowanie plecaka (tzn. takie, do którego nie będzie można dołożyć żadnego przedmiotu) o największej sumie użyteczności zabranych przedmiotów (zatem, być może, będziemy zmuszeni zabrać jakiś nieprzydatny przedmiot tylko po to, by dociążyć plecak).
Zauważmy, że jeśli będziemy chcieli zostawić w plecaku puste miejsce o wielkości to wszystkie przedmioty o rozmiarach nie większych niż
będą musiały znaleźć się w plecaku (inaczej moglibyśmy dołożyć do plecaka co najmniej jeden z nich). Posortujmy zatem przedmioty względem ich rozmiarów i podzielmy na grupę
przedmiotów "dużych" i
przedmiotów "małych", co po ewentualnym przenumerowaniu przedmiotów da nam
![w[1]⩾ w[2] ⩾...⩾ w[ j] > ℓ ⩾ w[ j + 1] ⩾ ... ⩾w[n].](/math/temat/informatyka/2015/08/26/Jeszcze_dwa_zadania_do_plecaka/5x-a34ecb95d188983bb6bbb552731653c1f7926708-dm-33,33,33-FF,FF,FF.gif)
Do plecaka na pewno weźmiemy wszystkie "małe" przedmioty o łącznym rozmiarze i użyteczności
Pozostałe przedmioty muszą zająć w plecaku miejsce o wielkości dokładnie
ale poza tym możemy je wybrać dowolnie. Zatem wystarczy, że rozwiążemy dla nich problem plecakowy maksymalizujący wartość zabranych przedmiotów - odpowiedzią będzie
Jeśli przeiterujemy po wartościach w kolejności malejącej, to każdy przedmiot dokładnie raz zmieni swój status z "małego" na "duży". Możemy więc na bieżąco rozwiązywać problem plecakowy i uaktualniać wartości
i
Wtedy koszt każdej takiej zmiany wyniesie
a cały algorytm będzie miał złożoność czasową