Кароче есть ли готовый алгоритм или нет вы скажите? :)
Раскидать "неоптимальным" образом по условным "потокам".
На первом шаге выбираем наибольшие файлы и раскидываем их по потокам.
Дальше выбираем поток с минимальной получившейся длиной и добавляем к нему следующий по величине файл.
Он остался минимумом? Добавим ещё.
Новый минимум? Добавляем к новому.
И так пока не раскидаем всё.
Берём максимально длинный поток и минимально длинный. Если можно произвести "обмен", при котором разница максимум-минимум среди всех потоков уменьшится, произвести его (длину файлов для обмена прикидывать как ближайшую искомую разницу между максимальным по длине и минимальным по длине потоком).
Обмен можно считать хоть полным перебором вариантов.
Опять берём максимально и минимально длинный, повторяем.
Когда обмена произвести уже нельзя -- закончили.
Досортировать в потоках файлы по размеру, от больших к меньшим.
"Развернуть" полученные данные:
1) из всех потоков выбираем "самый маленький из самых больших файлов", он идёт первым в одном из потоков. Пишем время завершения работы для потока.
2) берём следующий за ним файл в этом потоке. Обновляем время завершения.
3) берём второй по длине прогона из первых в потоках файлов, аналогично пишем следующий за ним и обновляем время завершения.
И так далее -- у нас всегда есть следующее время завершения и следующий файл.
Получится не оптимум, но нечто близкое к нему.