Jeśli dobrze rozumiem, po prostu posortuj listę razy i zgrupuj pierwsze trzy, następne trzy, w górę w pierwszej trójce.
EDIT: Ja nie rozumiem
Tak, chodzi o to, aby zabrać ludzi N i grupę ich do N/3 zespołów, dzięki czemu średni czas N/3 drużyny [zamiast 3 ludzie w każdym zespole, jak błędnie zinterpretowałem] jak najbliżej. W tym przypadku, myślę, że możesz zacząć od sortowania sterowników N w malejącej kolejności. Następnie zainicjuj pustą listę zespołów N/3. Następnie dla każdego kierowcy w malejącej kolejności czasu okrążenia, przydzielaj je drużynie z najmniejszym bieżącym łącznym czasem okrążenia (lub jedną z tych drużyn, w przypadku remisów). Jest to wariant prostego algorytmu pakowania bin.
Oto prosta implementacja Pythona:
times = [47.20, 51.14, 49.95, 48.80, 46.60, 52.70, 57.65, 55.45, 52.30, 59.90, 49.24, 47.88, 51.11, 53.20, 48.90, 45.90, 54.43, 52.38, 49.90, 44.31, 58.12, 61.23, 49.38, 48.39]
Nteams = len(times)/3
team_times = [0] * Nteams
team_members = [[]] * Nteams
times = sorted(times,reverse=True)
for m in range(len(times)):
i = team_times.index(min(team_times))
team_times[i] += times[m]
team_members[i] = team_members[i] + [m]
for i in range(len(team_times)):
print(str(team_members[i]) + ": avg time " + str(round(team_times[i]/3,3)))
którego wyjście jest
[0, 15, 23]: avg time 51.593
[1, 14, 22]: avg time 51.727
[2, 13, 21]: avg time 51.54
[3, 12, 20]: avg time 51.6
[4, 11, 19]: avg time 51.48
[5, 10, 18]: avg time 51.32
[6, 9, 17]: avg time 51.433
[7, 8, 16]: avg time 51.327
(Zauważ, że liczba członków zespołu odnosić się do nich w kolejności czasu okrążenia malejącym, zaczynając od 0, a niż do pierwotnego zamówienia).
Jedną z kwestii jest to, że jeśli czasy są bardzo zróżnicowane, nie ma żadnych ograniczeń co do liczby graczy w każdej drużynie dokładnie 3. Jednakże, dla twoich celów, może to jest w porządku, jeśli zamyka przekaźnik, i prawdopodobnie jest to rzadkie zjawisko, gdy rozpiętość w czasie jest znacznie mniejsza niż średni czas.
EDIT Jeśli chcemy tylko 3 zawodników z każdej drużyny, we wszystkich przypadkach, wówczas kod może być modyfikowany do trywialnie na każdym kroku odnaleźć drużyna z najmniejszą całkowity czas okrążenia, które nie mają już trzy przydzieleni gracze.Wymaga to niewielkiej modyfikacji w głównym bloku kodu:
times = sorted(times,reverse=True)
for m in range(len(times)):
idx = -1
for i in range(Nteams):
if len(team_members[i]) < 3:
if (idx == -1) or (team_times[i] < team_times[idx]):
idx = i
team_times[idx] += times[m]
team_members[idx] = team_members[idx] + [m]
Na przykład błąd w pytaniu powyżej rozwiązanie jest oczywiście identyczne, ponieważ nie próbują dopasować bardziej lub mniej niż 3 graczy jednej drużyny.
Jesteście sir, wyszliście poza to! Twój algorytm to dokładnie to, czego szukałem, a odchylenie standardowe jest lepsze niż wszystko, co spodziewałem się osiągnąć. Dziękuję Ci! – noirsette
Nie. Załóżmy, że dane są normalnie dystrybuowane. Następnie, wybierając 8 grup, dostaniesz 8 grup, w których nie ma 8 grup danych. Rzeczywiście, przypuśćmy, że ktoś chce 3 grup, ale istnieją 4 grupy. Ten algorytm arbitralnie łączy dwie z tych grup razem. Być może zrzuci to dwie najlepsze grupy razem, gdzie mądrą rzeczą do oddzielenia drużyn byłoby zrzucenie dwóch dolnych grup razem. Prawdopodobnie możesz użyć sprawdzania krzyżowego na tym algorytmie, aby wybrać najlepszą liczbę grup, ale co, jeśli liczba grup, które wybiera, nie jest numerem, który chcesz? – Scott
@Scott: użytkownik określa liczbę grup, ograniczoną liczbą i rozmiarem ras, które chcą uruchomić (przeczytaj post OP: "generowanie grup 3 osób o najbliższym średnim czasie okrążenia"). Algorytm nie wybiera liczby grup, znajduje jedynie najlepsze grupy z podanym numerem użytkownika. Twoja krytyka jest poprawna, ale dla innego problemu. – Richard