Biorąc pod uwagę listę ocen graczy, jestem zobowiązany do podzielenia graczy (tj. Ocen) na dwie grupy tak uczciwie, jak to możliwe. Celem jest zminimalizowanie różnicy między skumulowaną oceną drużyn. Nie ma żadnych ograniczeń co do tego, w jaki sposób mogę podzielić graczy na drużyny (jedna drużyna może mieć 2 graczy, a druga drużyna może mieć 10 graczy).
Na przykład: [5, 6, 2, 10, 2, 3, 4]
powinien wrócić([6, 5, 3, 2], [10, 4, 2])
Chciałbym znać algorytm rozwiązania tego problemu. Pamiętaj, że biorę kurs wprowadzający do programowania online, więc proste algorytmy byłyby mile widziane.
Używam następującego kodu, ale z jakiegoś powodu narzędzie do sprawdzania kodów online twierdzi, że jest niepoprawne.
def partition(ratings):
set1 = []
set2 =[]
sum_1 = 0
sum_2 = 0
for n in sorted(ratings, reverse=True):
if sum_1 < sum_2:
set1.append(n)
sum_1 = sum_1 + n
else:
set2.append(n)
sum_2 = sum_2 + n
return(set1, set2)
Aktualizacja: skontaktowałem się z instruktorami i powiedziano mi, że powinienem zdefiniować inną funkcję „pomocnika” wewnątrz funkcji, aby sprawdzić wszystkie różne kombinacje, a następnie muszę sprawdzić minimalną różnicę.
Odpowiedzi:
Uwaga: Zredagowano, aby lepiej obsługiwać przypadek, gdy suma wszystkich liczb jest nieparzysta.
Cofanie jest możliwością tego problemu.
Pozwala na badanie wszystkich możliwości rekurencyjnie, bez potrzeby dużej ilości pamięci.
Zatrzymuje się, gdy tylko zostanie znalezione optymalne rozwiązanie:
sum = 0
gdziesum
jest różnica między sumą elementów zestawu A i sumą elementów zestawu B. EDYCJA: zatrzymuje się tak szybkosum < 2
, aby obsłużyć przypadek, w którym suma wszystkich liczb jest nieparzysty, tzn. odpowiada minimalnej różnicy równej 1. Jeśli ta suma globalna jest parzysta, minimalna różnica nie może być równa 1.Pozwala to wdrożyć prostą procedurę przedwczesnego porzucenia :
w danym momencie, jeśli
sum
jest wyższa niż suma wszystkich pozostałych elementów (tj. Nie umieszczonych w A lub B) plus wartość bezwzględna uzyskanego minimum, możemy zrezygnować z badania bieżąca ścieżka, bez badania pozostałych elementów. Ta procedura jest zoptymalizowana dzięki:Oto pseudo-kod
Inicjalizacja:
a[]
sum_back[i] = sum_back[i+1] + a[i];
min_diff = sum_back[0];
a[0]
A -> indeksi
badanego elementu jest ustawiony na 1up_down = true;
: ta wartość logiczna wskazuje, czy aktualnie idziemy do przodu (prawda), czy do tyłu (fałsz)Podczas pętli:
Jeśli (up_down): naprzód
sum_back
sum
zgodnie z tym wyboremif (i == n-1)
: LEAF -> sprawdź poprawność optymalnej wartości i zwróć, jeśli nowa wartość jest równa 0 (EDYCJA:)if (... < 2)
; idź wsteczJeśli (! Updown): wstecz
i == 0
: powrótsum
wartośćOto kod w C ++ (Przepraszamy, nie znam Python)
źródło
if I == 0
. Przetestowałem to, zastępując 10 na 11 w twoim przykładzieMyślę, że powinieneś zrobić następne ćwiczenie sam, w przeciwnym razie nie nauczysz się wiele. Jeśli chodzi o ten, oto rozwiązanie, które próbuje wdrożyć porady Twojego instruktora:
Wynik:
Zauważ, że ten wynik jest inny niż pożądany, ale oba są poprawne.
Algorytm ten opiera się na fakcie, że aby wybrać wszystkie możliwe podzbiory danego zestawu z N elementami, możesz wygenerować wszystkie liczby całkowite z N bitów i wybrać I-ty element w zależności od wartości I-tego bitu. Pozostawiam wam dodanie kilku linii, aby zatrzymać się, gdy tylko
best_distance
zero wyniesie (bo oczywiście nie może być już lepiej).Trochę bitów (zwróć uwagę, że
0b
jest to przedrostek liczby binarnej w Pythonie):Liczba binarna:
0b0111001 == 0·2⁶+1·2⁵+1·2⁴+1·2³+0·2²+0·2¹+1·2⁰ == 57
Prawo przesunięty o 1:
0b0111001 >> 1 == 0b011100 == 28
Lewy przesunięty o 1:
0b0111001 << 1 == 0b01110010 == 114
Prawo przesunięty o 4:
0b0111001 >> 4 == 0b011 == 3
Bitowe
&
(i):0b00110 & 0b10101 == 0b00100
Aby sprawdzić, czy 5. bit (indeks 4) ma wartość 1:
(0b0111001 >> 4) & 1 == 0b011 & 1 == 1
Jeden z 7 zerami:
1 << 7 == 0b10000000
7 z nich:
(1 << 7) - 1 == 0b10000000 - 1 == 0b1111111
Wszystkie kombinacje 3-bitowe:
0b000==0
,0b001==1
,0b010==2
,0b011==3
,0b100==4
,0b101==5
,0b110==6
,0b111==7
(uwaga0b111 + 1 == 0b1000 == 1 << 3
)źródło
Robi to następujący algorytm:
a
, nieparzystych na liście,b
aby rozpocząća
ib
jeśli zmiana jest lepszaDodałem drukowane wyciągi, aby pokazać postęp na twojej przykładowej liście:
Wynik:
źródło
Ponieważ wiem, że muszę wygenerować wszystkie możliwe listy, muszę stworzyć funkcję „pomocnika”, aby pomóc wygenerować wszystkie możliwości. Po zrobieniu tego, naprawdę sprawdzam minimalną różnicę, a kombinacja list z tą minimalną różnicą jest pożądanym rozwiązaniem.
Funkcja pomocnicza jest rekurencyjna i sprawdza wszystkie możliwości kombinacji list.
Przykłady:
r = [1, 2, 2, 3, 5, 4, 2, 4, 5, 5, 2]
optymalna partycja to:([1, 2, 2, 3, 5, 4], [2, 4, 5, 5, 2])
z różnicą1
.r = [73, 7, 44, 21, 43, 42, 92, 88, 82, 70]
, optymalna partycja byłaby:([73, 7, 21, 92, 88], [44, 43, 42, 82, 70])
z różnicą0
.źródło
Oto dość skomplikowany przykład, przeznaczony raczej do celów edukacyjnych niż do działania. Wprowadza kilka interesujących pojęć w języku Python, takich jak listy i generatory, a także dobry przykład rekurencji, w których przypadki graniczne należy odpowiednio sprawdzać. Rozszerzenia, np. Obowiązują tylko drużyny z taką samą liczbą graczy, można łatwo wdrożyć w odpowiednich indywidualnych funkcjach.
Wynik:
źródło
Biorąc pod uwagę, że chcesz nawet drużyn, znasz docelowy wynik ocen każdej drużyny. Jest to suma ocen podzielona przez 2.
Poniższy kod powinien zrobić to, co chcesz.
Wynik
Istnieją inne podziały, które mają to samo
fairness
wszystkie są dostępne do znalezienia w kratce strong_ratings, po prostu wybieram pierwszy, ponieważ będzie on zawsze istniał dla każdej listy ocen, którą przekazujesz (pod warunkiemlen(ratings) > 1
).źródło
Chciwe rozwiązanie może dać rozwiązanie nieoptymalne. Oto dość proste chciwe rozwiązanie, pomysł polega na posortowaniu listy w kolejności malejącej, aby zmniejszyć efekt dodawania ocen w wiadrze. Ocena zostanie dodana do tego segmentu, którego suma ocen jest mniejsza
Wynik :
Edytować:
Innym podejściem będzie wygenerowanie wszystkich możliwych podzbiorów listy. Załóżmy, że masz l1, który jest jednym z podzbiorów listy, a następnie możesz łatwo uzyskać listę l2, tak że l2 = lista (oryginalna) - l1. Liczba wszystkich możliwych podzbiorów listy o rozmiarze n wynosi 2 ^ n. Możemy je oznaczyć jako sekwencję liczb całkowitych od 0 do 2 ^ n -1. Weźmy przykład, powiedzmy, że masz listę = [1, 3, 5], a następnie żadna z możliwych kombinacji nie wynosi 2 ^ 3, tj. 8. Teraz możemy napisać wszystkie kombinacje w następujący sposób:
Rozwiązanie:
Wynik :
źródło