Форум программистов, компьютерный форум, киберфорум
Алгоритмы
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.57/21: Рейтинг темы: голосов - 21, средняя оценка - 4.57
0 / 0 / 0
Регистрация: 01.05.2021
Сообщений: 5

Задача поиска подмножеств с минимальной суммой Amazon

01.05.2021, 16:22. Показов 4578. Ответов 41

Студворк — интернет-сервис помощи студентам
Есть список задач - массив чисел. Каждое число представляет собой сложность задачи. Задачи идут в строгом порядке, который нельзя менять. Так же дано количество дней. Сложность дня определяется самой сложной задачей, решенной в этот день. 
Нужно написать функцию, которая разобьет задачи по дням так, чтобы общая сложность (сумма) было минимальная. 


Пример 1:

Задачи [3, 1, 4, 2, 5]
2 дня.

Решение:

первый день [3] -> 3, 

второй день [1, 4, 2, 5] -> 5 (т.к. Сложность дня определяется самой сложной задачей)
3 +5 = 8


Пример 2:

Задачи [2, 4, 7, 3, 5, 1, 6]
3 дня.

Решение:

первый день [2] -> 2,

второй день [4] -> 4
Третий день [73516] -> 7
2+ 4 + 7 = 13


Ищу идеи для решения сложностью меньше O(n^m)
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.05.2021, 16:22
Ответы с готовыми решениями:

Задача по массивам. Найти строку с минимальной суммой и поставить ее на место первой строки
Дана матрица размерностью NxM. Найти строку с минимальной суммой и поставить ее на место первой строки. Заранее спасибо!

Найти столбец с минимальной суммой и вывести столбец с минимальной суммой
Найти столбец с минимальной суммой и вывести столбец с минимальной суммой

В заданной матрице поменять строку с минимальной суммой со строкой с максимальной суммой
помогите с кодом

41
698 / 572 / 75
Регистрация: 20.09.2014
Сообщений: 3,700
01.05.2021, 21:18
n - количество задач
m - количество дней
Основная мысль заключается в том, что задача с максимальной сложностью должна преимущественно "съедать" задачи с субмаксимальной сложностью. Например, в примере 2 задача сложности 7 "съедает" (экранирует) задачи сложности 6 и 5. При этом следует понимать, что сама задача сложности 7 не может быть экранирована никакой другой задачей. Именно от этой семерки и надо отталкиваться.
Решаем пример 2 с самого начала. n=7, m=3. Итак, мы определяем, что задача 7 - это максимум. Ищем субмаксимум - 6. Пробуем объединить все задачи между 7 и 6 включительно. Так как при таком объединении остались две непокрытые задачи, то такое объединение допустимо, т.е. соблюдается условие n-|j-i|-1>=m-1, где i, j - индексы границы объединяемых задач. В нашей задаче i=3, j=7. Если условие соблюдается, то хорошо - максимум экранирует субмаксимум. Если условие не соблюдается, то тоже хорошо, вариант отсекается, не нужно производить дальнейшие вычисления. Когда задачи успешно объединились в один день, то задача сводится к меньшей задаче, в нашем случае к такой:
[2,4,7]
m=3
То есть количество дней не уменьшилось, уменьшилось только количество задач. Но мы видим, что новая задача тривиальна (n=m), имеет четкое решение 2+4+7=13 и не требует дальнейшего перебора.
Давайте вернемся к тому, что мы предположили, что нужно объединить задачи между 7 и 6. Но почему не проверить вариант объединения задач между 7 и 5? Или между 7 и 4? А почему объединять задачу 7 с любой другой, может начать перебор допустимых объединений с задачи 6? У нас нет доказательства, что объединение задач между 7 и 6 - оптимальное.

Добавлено через 1 час 31 минуту
Такой наивный алгоритм: перебираем размещения задач по дням, примеры перебора: [1,2,3], [1,2,4], [1,2,5] и т.д. Количество размещений: A(n,m) = n! / (n-m)!. Сложность алгоритма в любом случае не хуже O(n^m), при m~n имеет худшую сложность O(n^m).

Попробуем улучшить алгоритм. Для этого мы пробегаем по всем задачам и определяем, какие из них являются допустимыми кандидатами стать задачей первого дня.

В нашем примере: задачей первого дня могут быть задачи [2,4,7]. Перебираем между ними. В итоге задача поиска сводится к решению трех других задач меньшего размера [4,7,3,5,1,6], [7,3,5,1,6], [3,5,1,6], в этих задачах m=2. Рекурсия.

1. Решаем подзадачу [4,7,3,5,1,6], m=2. Допустимые кандидаты [4,7]. Задача сводится к задачам [7,3,5,1,6] и [3,5,1,6], m=1. Тривиальный случай m=1 решается просто - в этом случае ответом является максимальной сложная задача. Таким образом ветка 1 дает варианты [2,4,7], [2,7,6]

2. Решаем подзадачу [7,3,5,1,6], m=2. Допустимые кандидаты [7]. Задача снова сводится к задаче [3,5,1,6], m=1. Вариант ветки 2: [4,7,6].

3. Решаем подзадачу [3,5,1,6], m=2. Допустимые кандидаты [3,5]. Задача сводится к трем подзадачам [5,1,6], [1,6], m=1. Варианты ветки 3: [7,3,6], [7,5,6].

Итого всего 5 вариантов перебрали из n^m = 7^3 = 343 или n!/(n-m)! = 210. Даже я вручную полные вычисления не заколебался сделать.

Этот алгоритм не хуже O(n*m) в значительной мере. n*m = 7*3 = 21, а я перебрал 5 вариантов и этого достаточно.
1
Эксперт Python
 Аватар для Red white socks
4523 / 1899 / 336
Регистрация: 18.01.2021
Сообщений: 3,489
01.05.2021, 21:34
Цитата Сообщение от Mikhaylo Посмотреть сообщение
У нас нет доказательства, что объединение задач между 7 и 6 - оптимальное
Если не объединить эти задачи, то как минимум общая сложность будет не меньше 7+6+что-то, то есть не меньше 14. А объединяя получаем 13. Вот и всё.
0
0 / 0 / 0
Регистрация: 01.05.2021
Сообщений: 5
01.05.2021, 21:54  [ТС]
спасибо за ответ ,может я чего не понимаю
через экстремумы да идея тоже приходила, но решения не нашел
пример
[3145983712] m=4
по алгоритму
только [3] кандидат
3- [145983712] m=3
кандидаты [1459]
1-[45983712] m=2
кандидаты [459]
4-[5983712] m=1 9
5-[983712]m=1 9
9-[83712]m=1 8
4-[5983712] m=2
кандидаты [59]
5-[983712] m=1 9
9-[83712]m=1 8
5-[983712] m=2
кандидаты [9]
9-[83712]m=1 8
9-[83712] m=2
кандидаты [8]
8-[3712]m=1 7


итого ответ [3149] =17
но ответ [3912]=15
0
698 / 572 / 75
Регистрация: 20.09.2014
Сообщений: 3,700
01.05.2021, 22:40
кажется самый тяжелый случай для предложенного алгоритма:
[1,2,3,4,5,6,7]
m=3

Кандидаты на первое место: [1,2,3,4,5].

Ветка 1: подзадача [2,3,4,5,6,7], m=2
Ветка 2: подзадача [3,4,5,6,7], m=2)
Ветка 3: подзадача [4,5,6,7], m=2
Ветка 4: подзадача [5,6,7], m=2
Ветка 5: подзадача [6,7], m=2

Итого для самого сложного случая имеем общую по рекурсивной формуле:
Сложность(n,m) = (n-m)*(сумма сложностей задач меньшего размера(i, m-1), i=m...n-m).

Метод математической индукции:
Сложность(n,1) = n.
Сложность(n,m) = (n-m)*(сумма сложностей задач меньшего размера(i, m-1), i=m...n-m).
Следует:
Сложность(n,m-1) = (n-m-1)*(сумма сложностей задач меньшего размера(i, m-2), i=m-1...n-m-1).

Добавлено через 10 минут
Цитата Сообщение от munchkin Посмотреть сообщение
итого ответ [3149] =17
но ответ [3912]=15
Вы неправильно решили вручную: когда рассматривали кандидата 9, то после него кандидаты [3,7,1,2] не отметаются кандидатом 8, так как он может быть погашен предыдущим кандидатом (9).

Добавлено через 11 минут
Я бы так решил задачу в конце концов.


[3145983712] m=4
1. Найти максимально сложную задачу (9), эта задача особая и она в любом случае забирает для себя один день (m=m-1). Эта задача делится на две подзадачи - прямая [3145],m1=[0...m-1] и обратная [21738], m2=[0...m-1]. Решаются подзадачи, но в конце концов отсеиваются варианты по условию m1+m2=m-1.

Добавлено через 10 минут
Цитата Сообщение от Red white socks Посмотреть сообщение
Если не объединить эти задачи, то как минимум общая сложность будет не меньше 7+6+что-то, то есть не меньше 14. А объединяя получаем 13. Вот и всё.
7+6+что-то легко посчитать, а вот убедиться, что меньше сумма не найдется - для этого нужно перебрать все варианты. Число 13 вы взяли из ответа, а туда подглядывать нельзя. С другой стороны, вы кидаете идею, что при объединении 7-6 можно исключить довольно много вариантов перебора. Но, к сожалению, эффективный алгоритм не проглядывается.
1
Эксперт Python
 Аватар для Red white socks
4523 / 1899 / 336
Регистрация: 18.01.2021
Сообщений: 3,489
01.05.2021, 23:14
Цитата Сообщение от Mikhaylo Посмотреть сообщение
кажется самый тяжелый случай для предложенного алгоритма:
[1,2,3,4,5,6,7]
Если это выглядит как тяжелый случай, то с алгоритмом что-то не так, потому что ответ здесь виден сразу невооруженным взглядом.
У меня есть собственные мысли, но я подожду пока ТС напишет до чего дошел сам

Добавлено через 2 минуты
Цитата Сообщение от Mikhaylo Посмотреть сообщение
Число 13 вы взяли из ответа, а туда подглядывать нельзя
Да не из ответа я их взял, а из варианта после объединения 7 и 6
0
0 / 0 / 0
Регистрация: 01.05.2021
Сообщений: 5
02.05.2021, 00:01  [ТС]
Цитата Сообщение от Mikhaylo Посмотреть сообщение
1. Найти максимально сложную задачу (9), эта задача особая и она в любом случае забирает для себя один день (m=m-1). Эта задача делится на две подзадачи - прямая [3145],m1=[0...m-1] и обратная [21738], m2=[0...m-1]. Решаются подзадачи, но в конце концов отсеиваются варианты по условию m1+m2=m-1.
ничего не понял

[1,2,3,4,5,6,7]
m=3

максимум 7 и что дальше
Цитата Сообщение от Mikhaylo Посмотреть сообщение
какие из них являются допустимыми кандидатами стать задачей первого дня.
какие задачи являются допустимыми?
0
698 / 572 / 75
Регистрация: 20.09.2014
Сообщений: 3,700
02.05.2021, 09:09
munchkin, когда вы решали задачу [3145983712] m=4, то алгоритм в принципе был эффективным, но он работал правильно лишь для чисел, которые стоят до 9. Поэтому я предлагаю такой же алгоритм прогнать по массиву справа налево. Чтобы не писать зеркальную функцию, которая определяет, какие из них являются допустимыми кандидатами стать задачей последнего дня, я предлагаю развернуть сам массив в обратном порядке, а затем полученные ответы переворачивать.
То есть разбиваем задачу на две:
А. Задача [31459], m=4
Б. Задача [217389], m=4
Решение:
А. Задача [31459], m=4, кандидаты [3459]
А.1 Задача [1459], m=3, кандидаты [1459]
А.1.1 Задача [459], m=2, кандидаты [459]
А.1.1.1 Задача [59], m=1, кандидаты [9]
А.1.1.2 Задача [9], m=1, кандидаты [9]
А.1.1.3 Задача [], m=1, кандидаты []
А.1.2 Задача [59], m=2, кандидаты [59]
А.1.2.1 Задача [9], m=1, кандидаты [9]
А.1.2.2 Задача [], m=1, кандидаты []
А.1.3 Задача [9], m=2, кандидаты [9]
А.1.4 Задача [], m=2, кандидаты []
А.2 Задача [59], m=3, кандидаты [59]
А.2.1 Задача [9], m=2, кандидаты [9]
А.2.2 Задача [], m=2, кандидаты []
А.3 Задача [9], m=3, кандидаты [9]
А.4 Задача [], m=3, кандидаты []

Расписал все рекурсии до тех пор, пока задачи не вырождаются (n=0 or n=1 or m=0 or (m=1 and n>=1)). Это условие выхода из рекурсии.
Если n=0, то решений нет, рекурсия прерывается.
Если n=1, то решение единственное, рекурсия прерывается.
Если m=0, то нет решений, так как размещать последующие задачи уже некуда. Рекурсия прерывается.
Если m=1 и n>=1, то решение единственное, равное максимально сложной задаче. Рекурсия прерывается.

Развернем рекурсии. Очень помогает в этом мульти-индексация задач типа А.x.y.z..., где количество индексов указывает на каком месте находится найденный ответ, а сам индекс указывает на предыдущего члена в задаче более высокого порядка. Получим варианты ответов первой подзадачи: [3149], [3159], [319], [3459], [349], [359], [39], [459], [49], [59], [9].

Б. Задача [217389], m=4, кандидаты [2789]
Б.1 Задача [17389], m=3, кандидаты [1789]
Б.1.1 Задача [7389], m=2, кандидаты [789]
Б.1.1.1 Задача [389], m=1, кандидаты [9]
Б.1.1.2 Задача [9], m=1, кандидаты [9]
Б.1.1.3 Задача [], m=1, кандидаты []
Б.1.2 Задача [389], m=2, кандидаты [389]
Б.1.2.1 Задача [89], m=1, кандидаты [9]
Б.1.2.2 Задача [9], m=1, кандидаты [9]
Б.1.2.3 Задача [], m=1, кандидаты []
Б.1.3 Задача [9], m=2, кандидаты [9]
Б.1.4 Задача [], m=2, кандидаты []
Б.2 Задача [389], m=3, кандидаты [389]
Б.2.1 Задача [89], m=2, кандидаты [89]
Б.2.1.1 Задача [9], m=1, кандидаты [9]
Б.2.1.2 Задача [], m=1, кандидаты []
Б.2.2 Задача [9], m=2, кандидаты [9]
Б.2.3 Задача [], m=2, кандидаты []
Б.3 Задача [9], m=3, кандидаты [9]
Б.4 Задача [], m=3, кандидаты []

Ответы: [2179], [2189], [219], [2739], [2789], [279], [289], [29], [7389], [739], [79], [89], [9].

Добавлено через 22 минуты
Далее. Переворачиваем ответы задачи Б:
[9712], [9812], [912], [9372], [9872], [972], [982], [92], [9837], [937], [97], [98], [9].

Следующий шаг - склейка ответов задач А и Б. Склеивать надо по девятке и только такие склейки пригодны, которые дают ответы с m=4.
Для этого группируем ответы по длине массивов.
А4: [3149], [3159], [3459]
А3: [319], [349], [359], [459]
А2: [39], [49], [59]
А1: [9]
Б4: [9712], [9812], [9372], [9872], [9837]
Б3: [912], [972], [982], [937]
Б2: [92], [97], [98]
Б1: [9]

В каждой группе находим минимальные решения:
А4: [3149]
А3: [319]
А2: [39]
А1: [9]
Б4: [9712]
Б3: [912]
Б2: [92]
Б1: [9]

Итоговые варианты ответов после склейки (конкатенации) А+Б:
[3149], [3192], [3912], [9712].

Из них лучшие ответы задачи [3145983712], m=4: [3192], [3912] с суммой 15.

Добавлено через 8 минут
Примечание: когда я находил минимальные массивы в группах А4, А3, А2, А1, Б4, Б3, Б2, Б1, у меня всегда минимальным оказывался первый массив. Так как я ответы везде записывал аккуратно в том порядке, в котором выдает предлагаемый алгоритм, то может быть это возможность для усовершенствования алгоритма (отсечь некоторые лишние варианты перебора)?

Добавлено через 19 минут
munchkin, не сразу понял, что ваш алгоритм отличается от моего.
Короче, подходящими кандидатами стать задачей первого дня, являются те задачи, которые сложнее всех предыдущих по времени задач.

Например, [321] - здесь ни одна задача не может покрыть кандидата [3]. А здесь [3254] - два возможных кандидата [35], задача [4] не может покрыть задачу [5], а задачу [3] не может покрыть задача [2].
0
431 / 302 / 90
Регистрация: 03.12.2015
Сообщений: 741
02.05.2021, 11:55
С помощью динамического программирования задачу можно решить за O(N*N*M), где N - количество задач, M - количество дней

Алгоритм:
Пусть задачи хранятся в массиве X[i]

Заведем массив D[start_task, end_task], в котором будем хранить сложность дня, если для этого дня мы выбрали задачи с номерами от start_task до end_task. Заполнять массив будем так:
Code
1
D[start_task, end_task] = max X[i], где i = [start_task, end_task]
Заведем массив S[start_task, days], в котором будем хранить лучшее решение нашей проблемы - разделение всех задач из X (начиная со start_task), разбивая их на days дней. Заполнять массив будем так:
Code
1
S[start_task, days] = min D[start_task, i] + S[i+1, days-1], где i=[start_task, len(X)-1]
Итоговый ответ - значение S[0, количество дней]

Сложность:
Количество значений в массиве D - N*N, каждое значение рассчитывается за O(1), итого N*N
Количество значений в массиве S - N*M, каждое значение рассчитывается за O(N), итого N*N*M
Итоговая сложность: O(N*N*M)
1
0 / 0 / 0
Регистрация: 01.05.2021
Сообщений: 5
02.05.2021, 13:56  [ТС]
доработал обход через рекурсию вроде решилось, не нашел не верных кейсов
https://codepen.io/mun4kin/pen... itors=1112

Цитата Сообщение от vrm2 Посмотреть сообщение
С помощью динамического программирования задачу можно решить
Спасибо буду пытаться)
0
698 / 572 / 75
Регистрация: 20.09.2014
Сообщений: 3,700
02.05.2021, 19:48
Цитата Сообщение от munchkin Посмотреть сообщение
Блин, а можете поработать над именами переменных? Вы используете такие имена как max, str, arr, как будто вы не частный алгоритм реализовали, а математическую библиотеку какую-то.) Срочно проникнитесь идеями Domain driven development (DDD), который диктует, чтобы имена соответствовали терминам предметной области. Извините, max, str, arr и т.п. - это не отражает сути реальных величин, какие-то слишком общие. Я не разобрался в коде, не хочу.

Добавлено через 7 минут
Например, я использовал такой термин как "кандидаты", тогда пусть будет переменная candidates; еще термины "склейка", "ответы", "решения", "варианты", "группы", "переворот"; а еще лучше ухватитесь за термины предметной области из условия задачи - days, tasks, complexity. Эти термины применены в условии задачи, не отворачивайтесь от них.

Добавлено через 20 минут
Цитата Сообщение от vrm2 Посмотреть сообщение
С помощью динамического программирования
У меня вроде тоже все признаки динамического программирования. Если не ошибаюсь, сложность O(n*m).
0
0 / 0 / 0
Регистрация: 01.05.2021
Сообщений: 5
02.05.2021, 20:05  [ТС]
Цитата Сообщение от Mikhaylo Посмотреть сообщение
Блин, а можете поработать над именами переменных
спасибо за совет, поправлю
0
431 / 302 / 90
Регистрация: 03.12.2015
Сообщений: 741
02.05.2021, 21:22
Цитата Сообщение от Mikhaylo Посмотреть сообщение
У меня вроде тоже все признаки динамического программирования. Если не ошибаюсь, сложность O(n*m).
А можно более четко сформулировать алгоритм?
И расчета сложности я тоже не увидел
0
698 / 572 / 75
Регистрация: 20.09.2014
Сообщений: 3,700
05.05.2021, 06:31
Я пытаюсь написать алгоритм на Пайтоне, долго провозился, но сейчас понял, что я пытался склеить два списка не обычной конкатенацией, а с помощью .append(). Скоро выдам.
0
698 / 572 / 75
Регистрация: 20.09.2014
Сообщений: 3,700
05.05.2021, 21:06
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def idxmax(lst):
    '''Поиск индекса наибольшего числа в списке'''
    index_max = 0
    for index, item in enumerate(lst[1:]):
        if item > lst[index_max]:
            index_max = index + 1
    return index_max
 
 
def Find_first_day_candidates(task_complexity_list, n_days):
    '''Поиск всех задач-кандидадатов стать главной в первый день из списка задач'''
    n = len(task_complexity_list) # число задач в списке
    if (n == 0) or (n_days == 0): # Нет решения, выход из рекурсии
        return [[]]
    elif (n == 1): # одно решение, выход из рекурсии
        return [[task_complexity_list[0]]]
    elif (n >= 1 and n_days == 1): # одно решение, выход из рекурсии
        return [[max(task_complexity_list)]]
    
    last_candidate_index = 0
    candidates_list = []
    for current_candidate_index, task_complexity in enumerate(task_complexity_list):
        if task_complexity >= task_complexity_list[last_candidate_index]:
            # найден очередной кандидат, добавим его в список и назначаем его последним
            last_candidate_index = current_candidate_index
            answer_list = Find_first_day_candidates(task_complexity_list[current_candidate_index + 1:], n_days-1)
            # Свели задачу к задаче меньшего размера
            for prev_candidates in answer_list:
                seq = [task_complexity] + prev_candidates
                candidates_list.append(seq)
    return candidates_list
 
 
def Amazon_calc(task_complexity_list, n_days):
    '''Основная функция решения задачи от Amazon'''
    
    max_complexity_index = idxmax(task_complexity_list) # Индекс самой сложной задачи в условии
    
    # Решение прямой задачи [3, 1, 4, 5, 9], n_days=4 (задача А)
    task_forward = Find_first_day_candidates(task_complexity_list[:max_complexity_index+1], n_days)
    print('\n Ответы задачи А:', task_forward)  
    
    # Решение обратной задачи [2, 1, 7, 3, 8, 9], n_days=4 (задача Б)
    task_reverse = Find_first_day_candidates(task_complexity_list[max_complexity_index:][::-1], n_days)
    print('\n Ответы задачи Б:', task_reverse)
        
    group_forward = {}
    for seq in task_forward:
        group_forward.setdefault(len(seq),[])
        group_forward[len(seq)] += [seq];   
    print('\n Сгруппированные по количеству дней ответы группы А:', group_forward) 
    
    group_reverse = {}
    for seq in task_reverse:
        group_reverse.setdefault(len(seq),[])
        group_reverse[len(seq)] += [seq[::-1]];    
    print('\n Сгруппированные по количеству дней ответы группы Б + реверс:', group_reverse)
    
    group_forward_leaders = {}
    for days, sequences in group_forward.items():
        group_forward_leaders[days] = sequences[0]
        for seq in sequences[1:]:
            if sum(seq) < sum(group_forward_leaders[days]):
                group_forward_leaders[days] = seq
    print('\n Лидеры группы А:', group_forward_leaders)
    
    group_reverse_leaders = {}    
    for days, sequences in group_reverse.items():
        group_reverse_leaders[days] = sequences[0]
        for seq in sequences[1:]:
            if sum(seq) < sum(group_reverse_leaders[days]):
                group_reverse_leaders[days] = seq    
    print('\n Лидеры группы Б', group_reverse_leaders)
    
    final_candidates = []
    for days, seq in group_forward_leaders.items():
        if (n_days-days+1 in group_reverse_leaders):
            final_candidates.append(seq[:-1] + group_reverse_leaders[n_days-days+1])
    print('\n Окончательные кандидаты:', final_candidates)
    
    win_count = sum(final_candidates[0])
    winner = final_candidates[0]
    for candidate in final_candidates[1:]:
        if sum(candidate) < win_count:
            win_count = sum(candidate)
            winner = candidate
    print('\n Победитель:', winner)
    return
Запуск программы:
Python
1
Amazon_calc([3, 1, 4, 5, 9, 8, 3, 7, 1, 2], 4)
Вывод в лог (ответы):
Кликните здесь для просмотра всего текста
Ответы задачи А: [[3, 1, 4, 9], [3, 1, 5, 9], [3, 1, 9], [3, 4, 5, 9], [3, 4, 9], [3, 5, 9], [3, 9], [4, 5, 9], [4, 9], [5, 9], [9]]

Ответы задачи Б: [[2, 1, 7, 9], [2, 1, 8, 9], [2, 1, 9], [2, 7, 3, 9], [2, 7, 8, 9], [2, 7, 9], [2, 8, 9], [2, 9], [7, 3, 8, 9], [7, 3, 9], [7, 8, 9], [7, 9], [8, 9], [9]]

Сгруппированные по количеству дней ответы группы А: {4: [[3, 1, 4, 9], [3, 1, 5, 9], [3, 4, 5, 9]], 3: [[3, 1, 9], [3, 4, 9], [3, 5, 9], [4, 5, 9]], 2: [[3, 9], [4, 9], [5, 9]], 1: [[9]]}

Сгруппированные по количеству дней ответы группы Б + реверс: {4: [[9, 7, 1, 2], [9, 8, 1, 2], [9, 3, 7, 2], [9, 8, 7, 2], [9, 8, 3, 7]], 3: [[9, 1, 2], [9, 7, 2], [9, 8, 2], [9, 3, 7], [9, 8, 7]], 2: [[9, 2], [9, 7], [9, 8]], 1: [[9]]}

Лидеры группы А: {4: [3, 1, 4, 9], 3: [3, 1, 9], 2: [3, 9], 1: [9]}

Лидеры группы Б {4: [9, 7, 1, 2], 3: [9, 1, 2], 2: [9, 2], 1: [9]}

Окончательные кандидаты: [[3, 1, 4, 9], [3, 1, 9, 2], [3, 9, 1, 2], [9, 7, 1, 2]]

Победитель: [3, 1, 9, 2]


Добавлено через 7 минут
В алгоритме небольшие недочеты.

Например, здесь не перебираются все варианты:


Python
1
Amazon_calc([9,1,2,3,4,5,8], 4)
Добавлено через 6 минут
Нашел ошибку. Придется добавить цикл, который сделает итоговую сложность O(n*n*m).
0
431 / 302 / 90
Регистрация: 03.12.2015
Сообщений: 741
05.05.2021, 23:10
Решение
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import math
from functools import lru_cache
from typing import Tuple, List
 
TSection = Tuple[int, int]
 
def solve(tasks: List[int], days: int) -> Tuple[int, List[TSection]]:
    @lru_cache
    def day_value(start: int, end: int) -> int:
        if end < start:
            return -math.inf
        return max(tasks[end], day_value(start, end - 1))
 
    @lru_cache
    def best_variant(start: int, days: int) -> Tuple[int, List[TSection]]:
        if start >= len(tasks):
            return math.inf, []
 
        if days <= 1:
            end = len(tasks) - 1
            return day_value(start, end), [(start, end)]
 
        variants = []
        for end in range(start, len(tasks)):
            value, descriptions = best_variant(end + 1, days - 1)
            new_value = day_value(start, end) + value
            new_descriptions = [(start, end)] + descriptions
            new_variant = new_value, new_descriptions
            variants.append(new_variant)
        return min(variants)
 
    return best_variant(0, days)
Печать решения:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def print_solve(tasks: List[int], days: int) -> None:
    print(f'Tasks={tasks} Days={days}')
    print(f'Solve:')
    value, descriptions = solve(tasks, days)
    for start, end in descriptions:
        section = tasks[start: end + 1]
        print(f'Day {section} => max is {max(section)}')
    print(f'Total = {value}\n')
 
print_solve([3, 1, 4, 2, 5], 2)
print_solve([2, 4, 7, 3, 5, 1, 6], 3)
print_solve([3, 1, 4, 5, 9, 8, 3, 7, 1, 2], 4)
print_solve([1, 2, 3, 4, 5, 6, 7], 3)
print_solve([9, 1, 2, 3, 4, 5, 8], 4)
Результаты:
Tasks=[3, 1, 4, 2, 5] Days=2
Solve:
Day [3] => max is 3
Day [1, 4, 2, 5] => max is 5
Total = 8

Tasks=[2, 4, 7, 3, 5, 1, 6] Days=3
Solve:
Day [2] => max is 2
Day [4] => max is 4
Day [7, 3, 5, 1, 6] => max is 7
Total = 13

Tasks=[3, 1, 4, 5, 9, 8, 3, 7, 1, 2] Days=4
Solve:
Day [3] => max is 3
Day [1] => max is 1
Day [4, 5, 9, 8, 3, 7] => max is 9
Day [1, 2] => max is 2
Total = 15

Tasks=[1, 2, 3, 4, 5, 6, 7] Days=3
Solve:
Day [1] => max is 1
Day [2] => max is 2
Day [3, 4, 5, 6, 7] => max is 7
Total = 10

Tasks=[9, 1, 2, 3, 4, 5, 8] Days=4
Solve:
Day [9] => max is 9
Day [1] => max is 1
Day [2] => max is 2
Day [3, 4, 5, 8] => max is 8
Total = 20
0
698 / 572 / 75
Регистрация: 20.09.2014
Сообщений: 3,700
06.05.2021, 06:51
Да, алгоритм тот же.

Добавлено через 9 минут
Я бы не вводил переменную end, так как всегда end + 1 = next_start, т.е. достаточно свести задачу к определению того, какие задачи являются первыми. Мне кажется, так проще понимать, в духе динамического программирования. Это подчеркнет то, как задача бьется на более мелкие подзадачи.
0
Модератор
Эксперт функциональных языков программирования
3132 / 2279 / 469
Регистрация: 26.03.2015
Сообщений: 8,870
06.05.2021, 14:28
Цитата Сообщение от vrm2 Посмотреть сообщение
Решение
Динамическое программирование "сверху вниз" - перебор всех вариантов с кэшированием результатов промежуточных вычислений. Из-за того, что количество промежуточных вариантов ограничено, экспонента превращается в полином.

Можно заменить "неявное" кэширование с помощью внешней библиотеки на явное кэширование:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import math
from typing import Tuple, List
 
TSection = Tuple[int, int]
 
def solve(tasks: List[int], days: int) -> Tuple[int, List[TSection]]:
    n = len(tasks)
    d = [[0 for i in range(n)] for j in range(n)]
    v = [[(0, []) for i in range(n)] for j in range(n)]
 
    def day_value(start: int, end: int) -> int:
        if end < start:
            return -math.inf
        if d[start][end] != 0:
            return d[start][end]
        
        res = max(tasks[end], day_value(start, end - 1))
        d[start][end] = res
        return res
 
    def best_variant(start: int, days: int) -> Tuple[int, List[TSection]]:
        if start >= len(tasks):
            return math.inf, []
        if v[start][days] != (0, []):
            return v[start][days]
 
        if days <= 1:
            end = len(tasks) - 1
            return day_value(start, end), [(start, end)]
 
        variants = []
        for end in range(start, len(tasks)):
            value, descriptions = best_variant(end + 1, days - 1)
            new_value = day_value(start, end) + value
            new_descriptions = [(start, end)] + descriptions
            new_variant = new_value, new_descriptions
            variants.append(new_variant)
        
        res2 = min(variants)
        v[start][days] = res2
        return res2
 
    res3 = best_variant(0, days)
    print(f'd:')
    for k in range(n):
        print(f'{d[k]}')
    print(f'v:')
    for k in range(n):
        s = list(map(lambda x: x[0], v[k]))
        print(f'{s}')
    return res3
    
    
def print_solve(tasks: List[int], days: int) -> None:
    print(f'Tasks={tasks} Days={days}')
    print(f'Solve:')
    value, descriptions = solve(tasks, days)
    for start, end in descriptions:
        section = tasks[start: end + 1]
        print(f'Day {section} => max is {max(section)}')
    print(f'Total = {value}\n')
    
    
print_solve([2, 2, 2, 4, 1, 1, 1, 3], 4)
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Tasks=[2, 2, 2, 4, 1, 1, 1, 3] Days=4
Solve:
d:
[2, 2, 2, 4, 4, 4, 4, 4]
[0, 2, 2, 4, 4, 4, 4, 4]
[0, 0, 2, 4, 4, 4, 4, 4]
[0, 0, 0, 4, 4, 4, 4, 4]
[0, 0, 0, 0, 1, 1, 1, 3]
[0, 0, 0, 0, 0, 1, 1, 3]
[0, 0, 0, 0, 0, 0, 1, 3]
[0, 0, 0, 0, 0, 0, 0, 3]
v:
[0, 0, 0, 0, 9, 0, 0, 0]
[0, 0, 0, 8, 0, 0, 0, 0]
[0, 0, 6, 8, 0, 0, 0, 0]
[0, 0, 7, 8, 0, 0, 0, 0]
[0, 0, 4, 5, 0, 0, 0, 0]
[0, 0, 4, 5, 0, 0, 0, 0]
[0, 0, 4, inf, 0, 0, 0, 0]
[0, 0, inf, inf, 0, 0, 0, 0]
Day [2, 2, 2, 4] => max is 4
Day [1] => max is 1
Day [1] => max is 1
Day [1, 3] => max is 3
Total = 9
Было бы интереснее построить кэш "снизу вверх". Это обычно работает быстрее.

Порядок вычислений кэша (основной таблицы):
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
v[2, 2] = (6, [(2, 2), (3, 7)])
v[3, 2] = (7, [(3, 3), (4, 7)])
v[4, 2] = (4, [(4, 4), (5, 7)])
v[5, 2] = (4, [(5, 5), (6, 7)])
v[6, 2] = (4, [(6, 6), (7, 7)])
v[7, 2] = (inf, [(7, 7)])
v[1, 3] = (8, [(1, 1), (2, 2), (3, 7)])
v[2, 3] = (8, [(2, 3), (4, 4), (5, 7)])
v[3, 3] = (8, [(3, 3), (4, 4), (5, 7)])
v[4, 3] = (5, [(4, 4), (5, 5), (6, 7)])
v[5, 3] = (5, [(5, 5), (6, 6), (7, 7)])
v[6, 3] = (inf, [(6, 6), (7, 7)])
v[7, 3] = (inf, [(7, 7)])
v[0, 4] = (9, [(0, 3), (4, 4), (5, 5), (6, 7)])
Добавлено через 3 минуты
https://ideone.com/731sbY
0
Модератор
Эксперт функциональных языков программирования
3132 / 2279 / 469
Регистрация: 26.03.2015
Сообщений: 8,870
07.05.2021, 14:18
Строим кэш "снизу вверх":
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import math
from typing import Tuple, List
 
TSection = Tuple[int, int]
    
def solve(tasks: List[int], days: int) -> Tuple[int, List[TSection]]:
    n = len(tasks)
    m = n - days + 1
 
    d = [tasks]    
    for i in range(1, n):
        r = [max(d[i-1][j], d[i-1][j+1]) for j in range(n-i)]
        d.append(r)
 
    v = [[(0, []) for j in range(m)] for i in range(days)]
    for j in range(0, m):
        i = 0
        start = days - i - 1 + j
        k = n - 1 - start
        v[i][j] = d[k][start], [(start, start + k)]
    for i in range(1, days):
        for j in range(0, m):
            start = days - i - 1 + j
            variants = []
            for k in range(0, m - j):
                value, descriptions = v[i-1][j+k]
                new_value = d[k][start] + value
                new_descriptions = [(start, start + k)] + descriptions
                new_variant = new_value, new_descriptions
                variants.append(new_variant)
            res2 = min(variants)
            v[i][j] = res2
 
    print(f'd:')
    for k in range(n):
        print(f'{d[k]}')
 
    print(f'v:')
    for k in range(days):
        s = list(map(lambda x: x[0], v[k]))
        print(f'{s}')
 
    return v[days-1][0]
    
def print_solve(tasks: List[int], days: int) -> None:
    print(f'Tasks={tasks} Days={days}')
    value, descriptions = solve(tasks, days)
    print(f'Solve:')
    for start, end in descriptions:
        section = tasks[start: end + 1]
        print(f'Day {section} => max is {max(section)}')
    print(f'Total = {value}\n')
 
 
print_solve([2, 2, 2, 4, 1, 1, 1, 3], 4)
Вывод:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Tasks=[2, 2, 2, 4, 1, 1, 1, 3] Days=4
d:
[2, 2, 2, 4, 1, 1, 1, 3]
[2, 2, 4, 4, 1, 1, 3]
[2, 4, 4, 4, 1, 3]
[4, 4, 4, 4, 3]
[4, 4, 4, 4]
[4, 4, 4]
[4, 4]
[4]
v:
[4, 3, 3, 3, 3]
[6, 7, 4, 4, 4]
[8, 8, 8, 5, 5]
[9, 9, 9, 9, 6]
Solve:
Day [2, 2, 2, 4] => max is 4
Day [1] => max is 1
Day [1] => max is 1
Day [1, 3] => max is 3
Total = 9

з.ы.
Массив v не обязательно хранить целиком, так как нам нужна только предыдущая строка.
Последнюю строку в v не обязательно вычислять целиком, так как нам нужен только первый элемент.
0
431 / 302 / 90
Регистрация: 03.12.2015
Сообщений: 741
08.05.2021, 09:53
Сократил немного свой вариант
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def solve(tasks: List[int], days: int) -> Tuple[int, List[TSection]]:
    @lru_cache
    def best_variant(start: int, days: int) -> Tuple[int, List[TSection]]:
        if days <= 0:
            return 0 if start >= len(tasks) else math.inf, []
 
        variants = []
        day_value = -math.inf
        for end in range(start, len(tasks) - days + 1):
            day_value = max(day_value, tasks[end])
            value, descriptions = best_variant(end + 1, days - 1)
            variant = value + day_value, [(start, end)] + descriptions
            variants.append(variant)
        return min(variants)
 
    return best_variant(0, days)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
08.05.2021, 09:53
Помогаю со студенческими работами здесь

В двумерном массиве поменять местами строку с максимальной суммой с минимальной суммой
Нам задали написать 2 различные проги для такого задания В двумерном массиве поменять местами строку с максимальной суммой с минимальной...

Столбец матрицы с минимальной суммой элементов поменять со столбцом с максимальной суммой
#include &lt;math.h&gt; #include &lt;locale.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;conio.h&gt; using namespace std; main() {...

В целочисленной матрице поменять местами столбец с минимальной суммой со столбцом с максимальной суммой
Дана прямоугольная матрица nxm целых чисел (n,m&lt;10 – ввод с клавиатуры, значения элементов массива в диапазоне – вводятся случайным...

Массив: В произвольно заданной матрице размера 4*6 определить строку с максимальной суммой элементов и столбец с минимальной суммой.
В произвольно заданной матрице размера 4*6 определить строку с максимальной суммой элементов и столбец с минимальной суммой.

Разбиение множества на k подмножеств с одинаковой суммой
Можете привести примеры, где это можно использовать в жизни, пожалуйста. Примера 3-5.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru