Zadałem to pytanie na StackOverflow , ale myślę, że tutaj jest bardziej odpowiednie miejsce.
Jest to problem od kursu Wprowadzenie do algorytmów :
Musisz tablicę z liczb całkowitych dodatnich (tablica nie muszą być sortowane lub elementów unikalnych). Zaproponuj algorytm , aby znaleźć największą sumę elementów, która jest podzielna przez .
Przykład: . Odpowiedź to (z elementami )
Stosunkowo dynamicznie jest go znaleźć w przy użyciu programowania dynamicznego i przechowując największą sumę z resztą .
Ponadto, jeśli ograniczenia uwagę na ciągłej sekwencji elementów, łatwo znaleźć optymalną takiej sekwencji w czasie przechowywania cząstkowych sumy modulo niech , dla każdej reszty pamiętaj największy indeks taki, że , a następnie dla każdego rozważasz S [j] -S [i] gdzie j jest indeksem odpowiadającym r = S [i] \ bmod n .
Ale czy istnieje rozwiązanie czasu w przypadku ogólnym? Wszelkie sugestie będą mile widziane! Myślę, że ma to coś wspólnego z algebrą liniową, ale nie jestem pewien, co dokładnie.
Alternatywnie, czy można to zrobić w czasie ?
źródło
Odpowiedzi:
Oto kilka przypadkowych pomysłów:
Algorytm programowania dynamicznego można przerzucić, aby wyszukać najmniejszą sumę zamiast największej. Po prostu kończysz na szukaniu sumy zgodnej z resztą sumy całej tablicy, zamiast jednej przystawki do zera. Jeśli przetwarzamy elementy w kolejności rosnącej, czasami pozwala to na zakończenie algorytmu dynamicznego przed przetworzeniem całej tablicy.
Koszt wyniósłby , gdybyśmy przetworzyli elementów. W tym algorytmie nie ma dolnej granicy , ponieważ nie musimy sortować wszystkich elementów. Zajmuje tylko czas, aby uzyskać najmniejszych elementów.O(nk) k Ω(nlogn) O(nlogk) k
Jeśli zależy nam na zbiorze o dużych rozmiarach, zamiast zestawu o największej sumie, możemy być w stanie użyć mnożenia wielomianowego opartego na szybkiej transformacie Fouriera, aby rozwiązać problem w czas. Podobne do tego, co zrobiono w 3SUM, gdy zakres domen jest ograniczony. (Uwaga: użyj powtarzania kwadratu, aby przeprowadzić wyszukiwanie binarne, w przeciwnym razie otrzymasz gdzie jest liczbą pominiętych elementów.)O(n(logn)2(loglogn)) O(nk(logn)(loglogn)) k
Gdy jest złożone, a prawie wszystkie pozostałe są wielokrotnością jednego z czynników , można zaoszczędzić znaczny czas, skupiając się na pozostałych, które nie są wielokrotnością tego czynnika.n n
Gdy reszta
r
jest bardzo powszechna lub pozostało tylko kilka, śledzenie „następnego otwartego slotu, jeśli zaczniesz od tego miejsca i będziesz przechodzić dalejr
”, może zaoszczędzić wiele skanowania w poszukiwaniu skoków w otwarte miejsca czas.Możesz ogolić współczynnik logarytmiczny, śledząc jedynie osiągalność i używając masek bitowych (w odwróconym algorytmie dynamicznym), a następnie cofając się po osiągnięciu pozostałej wartości docelowej.
Algorytm programowania dynamicznego jest bardzo podatny na równoległe działanie. Z procesorem dla każdego gniazda bufora możesz przejść do . Alternatywnie, używając szerokości oraz dzielenia i zdobywania agregacji zamiast agregacji iteracyjnej, koszt głębokości obwodu może spaść aż do .O(n) O(n2) O(log2n)
(Meta) Podejrzewam, że podany przez ciebie problem dotyczy ciągłych sum. Jeśli powiązałeś się z rzeczywistym problemem, łatwo byłoby to zweryfikować. W przeciwnym razie jestem bardzo zaskoczony, jak trudny jest ten problem, biorąc pod uwagę, że został on przypisany w kursie o nazwie „Wprowadzenie do algorytmów”. Ale może omówiłeś w klasie sztuczkę, która czyni ją trywialną.
źródło
Mój proponowany algorytm wygląda następująco:
Suma dzieli się przez n, jeśli dodasz tylko sumy będące wielokrotnościami n.
Zanim zaczniesz, tworzysz mapę z int jako kluczem i listą indeksów jako wartością. Tworzysz także listę wyników zawierającą indeksy.
Następnie zapętlasz tablicę i dodajesz każdy indeks, którego mod n wynosi zero, do listy wyników. Dla każdego innego indeksu wykonaj następujące czynności:
Odejmujesz wartość mod n tego indeksu od n. Ten wynik jest kluczem do twojego hashapa, który przechowuje indeksy dla elementów o wymaganej wartości. Teraz dodajesz ten indeks do listy w haszapie i idziesz dalej.
Po zakończeniu zapętlania tablicy macierz oblicza dane wyjściowe. Robisz to, sortując każdą listę w haszapie zgodnie z wartością wskazywaną przez indeks. Teraz weźmiesz pod uwagę każdą parę w haszpie sumującą się do n. Więc jeśli n = 7, przeszukujesz hashap dla 3 i 4. Jeśli masz wpis w obu, bierzesz dwie największe wartości, usuwasz je z ich list i dodajesz do swojej listy wyników.
Ostatnia rekomendacja: nadal nie testowałem algorytmu, napisz test z nim za pomocą algorytmu brutalnej siły.
źródło
użyj tej metody DP z ( /programming/4487438/maximum-sum-of-non-consecutive-elements?rq=1 ):
Biorąc pod uwagę tablicę A [0..n], niech M (i) będzie optymalnym rozwiązaniem wykorzystującym elementy o indeksach 0..i. Następnie M (-1) = 0 (użyte w nawrocie), M (0) = A [0], a M (i) = max (M (i - 1), M (i - 2) + A [i ]) dla i = 1, ..., n. M (n) to rozwiązanie, którego chcemy. To jest O (n) . Możesz użyć innej tablicy do zapisania wyboru dokonanego dla każdego podproblemu, aby odzyskać wybrane elementy.
Zmień rekurencję na M (i) = max (M (i - 1), M (i - 2) + A [i]) tak, że jest przechowywana tylko wtedy, gdy jest podzielna przez N
źródło