2016-09-13 18 views
6

Jeśli są n nieposortowane wagi i muszę znaleźć najmniejszą liczbę odważników, aby uzyskać przynajmniej wagę W. Jak je znaleźć w O(n)?Jak wybrać najmniejszą liczbę odważników, aby uzyskać całkowitą masę w czasie O (n)?

+0

Czy istnieje limit wag? – sashas

+0

proszę, dane przykładowe - żebyśmy mogli to sprawdzić. Przykładowy wynik na tych danych. A twoja próba kodowania rozwiązania? –

+0

Można to zrobić za pomocą szybkiego wyboru. –

Odpowiedz

3

Ten problem ma wiele metod rozwiązania:

Metoda 1 - Sortowanie - O (nlogn)
Myślę, że najbardziej trywialne jeden byłoby uporządkować w kolejności malejącej, a następnie podjąć pierwsze elementy K które dają sumę co najmniej W. Złożoność czasu będzie wynosiła O(nlogn).

Metoda 2 - max stosu - O (n + klogn)
Innym sposobem jest użycie max sterty. Tworzenie sterty zajmie O(n), a następnie wyodrębnianie elementów, aż uzyskamy całkowitą sumę co najmniej W. Każda ekstrakcja zajmie O(logn), więc całkowita złożoność czasu będzie wynosić O(klogn), gdzie k jest liczbą elementów, które musieliśmy wyodrębnić ze sterty .

Metoda 3 - Korzystanie Min Heap - O (nlogk)
Dodanie tej metody, która JimMischel sugerowane w komentarzach poniżej.
Tworzenie minimalnej sterty z pierwszymi elementami k na liście, która wynosi co najmniej W. Następnie wykonaj iterację nad pozostałymi elementami i jeśli jest większa niż minimalna (stertowanie), wymień między nimi.
W tym momencie może być tak, że mamy więcej elementów tego, co faktycznie potrzebujemy, aby uzyskać W, więc wyodrębnimy minimalne wartości, dopóki nie osiągniemy limitu. W praktyce, w zależności od relacji pomiędzy

find_min_set(A,W) 
    currentW = 0 
    heap H //Create empty heap 

    for each Elem in A 
     if (currentW < W) 
      H.add(Elem) 
      currentW += Elem 
     else if (Elem > H.top()) 
      currentW += (Elem-H.top()) 
      H.pop() 
      H.add(Elem) 

    while (currentW-H.top() > W) 
     currentW -= H.top() 
     H.pop() 

Metoda ta może być nawet szybciej w praktyce, w zależności od relacji pomiędzy k i n. Zobacz when theory meets practice.

Metoda 4 - O (n)
Najlepszy sposób może myślę zostanie przy użyciu pewnego rodzaju quickselect zachowując jednocześnie całkowitej wagi i zawsze przegród z medianą jako przegub.

Najpierw zdefiniować kilka rzeczy:

sum(A) - łączna suma wszystkich elementów w tablicy A.
num(A) - Liczba elementów w tablicy A.
med(A) - Mediana tablicy A.

find_min_set(A,W,T) 
    //partition A 
    //L contains all the elements of A that are less than med(A) 
    //R contains all the elements of A that are greater or equal to med(A) 
    L, R = partition(A,med(A)) 
    if (sum(R)==W) 
     return T+num(R) 
    if (sum(R) > W) 
     return find_min_set(R,W,T) 
    if (sum(R) < W) 
     return find_min_set(L,W-sum(R),num(R)+T) 

Wywołanie tej metody przez find_min_set(A,W,0).

Runtime Złożoność:

  • Znalezienie mediana O(n).
  • Partycjonowanie to O(n).
  • Każde wywołanie rekurencyjne zajmuje połowę rozmiaru tablicy.
  • Podsumowując, otrzymujemy następujący stosunek: T(n) = T(n/2) + O(n), który jest taki sam jak średni przypadek quickselect = O(n).

Uwaga: Gdy wszystkie wartości są unikatowe zarówno najgorszy przypadek i średnia złożoność jest rzeczywiście O(n). Z możliwymi zduplikowanymi wartościami, średnia złożoność nadal wynosi O(n), ale najgorszy przypadek to O(nlogn) przy użyciu metody wybierania liczby przestawnej za pomocą metody Median of medians.

+0

@trincot Byłoby to prawdą, gdybyś szukał zestawu o wadze * dokładnie * 'W', ale jeśli po prostu chcesz * co najmniej * 'W', chciwie wybierając największy pozostały element jest to, co chcesz. Metody 1 i 2 są w porządku; Metoda 3 działa, ale nie sądzę, że jej czas działania jest bardziej ograniczony niż metoda 2. – chepner

+0

Ach tak, @chepner, teraz widzę tytuł pytania jest nieco mylący. Zrobiłem to, aby oznaczać * dokładnie *, co okazało się nie być tym, o co go proszono. Dzięki za wytłumaczenie. – trincot

+0

@chepner Myślę, że tak. Wybór mediany to O (n), partycjonowanie to O (n). A wybierając medianę, obiecuje, że każda rekursja zostanie wywołana z połową rozmiaru tablicy, co oznacza, że ​​obiecuje czas wykonania dla przeciętnego przypadku wyboru szybkiego, który jest O (n). Czy czegoś brakuje? –