Informatyczny kącik olimpijski
Sklep ze słodyczami
Tym razem zadanie Candies z Bałtyckiej Olimpiady Informatycznej z 2010 roku.

Zadanie. W sklepie znajduje się paczek z cukierkami,
-ta z nich zawiera
cukierków. Sklepikarz może sprzedawać jedynie całe paczki, więc jeśli w sklepie są cztery paczki zawierające 1, 3, 4 i 4 cukierki, to może on obsłużyć następnego klienta tylko wtedy, gdy ten złoży zamówienie jednego z 9 rozmiarów (konkretnie gdy poprosi o 1, 3, 4, 5, 7, 8, 9, 11 lub 12 cukierków). Sklepikarz zastanawia się, jak bardzo mógłby zwiększyć liczbę możliwości, gdyby zamienił liczbę cukierków w jednej z paczek. Przykładowo, po wyrzuceniu jednej paczki z 4 cukierkami i dodaniu paczki z 9 cukierkami, liczba możliwych do zrealizowania zamówień zwiększy się do 13 (będą to 1, 3, 4, 5, 7, 8, 9, 10, 12, 13, 14, 16, 17). Jeśli istnieje więcej niż jedno optymalne rozwiązanie, w którym sklepikarz zamienia paczkę z
cukierkami na paczkę z
cukierkami, należy podać to, w którym para
jest minimalna leksykograficznie.
Załóżmy na początek, że wyrzuciliśmy którąś z paczek, a zestaw pozostałych paczek umożliwia zrealizowanie zamówień o wielkościach
(zakładamy przy tym, że zamówienie
również jest poprawne). Jeśli dodamy do tego zestawu paczkę
cukierków, to będziemy mogli dodatkowo zrealizować zamówienia
a zatem jeśli
nie jest równe żadnej różnicy
to liczba zamówień wzrośnie dwukrotnie. Możemy to sobie zagwarantować, dodając wystarczająco dużą paczkę, np. rozmiaru
Rozwiązanie zadania można zatem podzielić na dwie części: znalezienie paczki
której wyrzucenie jak najmniej zmniejszy liczbę możliwych zamówień, oraz znalezienie jak najmniejszej paczki
która spowoduje dwukrotne zwiększenie liczby możliwych zamówień.
Zadanie to jest pewną wariacją na temat problemu plecakowego (o którym pisaliśmy m.in. w numerze 6/2013). W szczególności wyznaczenie liczby zamówień możliwych do zrealizowania przez początkowy zestaw paczek to zastosowanie tego algorytmu do przedmiotów rozmiarów
i plecaka o udźwigu
Pseudokod algorytmu znajduje się obok. Przypomnijmy istotne dla nas kwestie: czas działania algorytmu wynosi analizuje on przedmioty pojedynczo (w czasie
każdy), aktualizując tablicę
(w wynikowej tablicy mamy
jeśli zamówienie rozmiaru
może być zrealizowane), oraz dla ostatecznego wyniku nie ma znaczenia kolejność, w której przedmioty są analizowane. Możemy abstrahować od szczegółów implementacyjnych i zamknąć go w strukturze danych, która w czasie
będzie umożliwiała wykonywanie trzech operacji: zrobienie kopii struktury, dodanie nowego przedmiotu oraz wyznaczenie liczby zamówień realizowanych przez dodane przedmioty.
Aby znaleźć paczkę potrzebujemy rozwiązać problem plecakowy dla każdego podzbioru
przedmiotów. Jeśli rozpatrzymy każdy z tych podzbiorów niezależnie, dostaniemy algorytm o złożoności czasowej
Możemy postąpić nieco sprytniej. Będziemy utrzymywać listę struktur danych (na początek zaczynamy z jedną pustą strukturą danych). Teraz, dopóki struktury na liście zawierają mniej niż przedmiotów, to dla każdej struktury
dzielimy zbiór przedmiotów
niewystępujących w tej strukturze na dwa w miarę równe podzbiory
i
a strukturę
zastępujemy jej kopiami
i
do których dodajemy przedmioty odpowiednio z podzbiorów
i
(patrz rysunek). Jeśli dla uproszczenia założymy, że
jest potęgą dwójki, to w
-tej fazie tego algorytmu wygenerujemy
struktur, do każdej z nich dodając
przedmiotów. Zatem złożoność czasowa każdej z
faz wyniesie
czyli rozwiązanie problemu plecakowego dla wszystkich podzbiorów
przedmiotów zajmie czas
Pozostaje teraz znalezienie minimalnej liczby która nie będzie równa żadnej różnicy
Ponieważ
są zamówieniami generowanymi przez wybrany podzbiór
paczek, to wszystkie różnice będą generowane przez zbiór
Wystarczy zatem rozwiązać problem plecakowy dla takich przedmiotów (w naszej wersji tego problemu przedmioty o ujemnym rozmiarze nie stanowią problemu, należy jednak zwrócić uwagę na rozmiar tablicy i poprawną kolejność pętli) i zwrócić jako
minimalną dodatnią liczbę, dla której
Czas działania tej części rozwiązania to