@m-kicherov

Как оптимизировать данный код?

Добрый день. Задача следующая: в функцию передается словарь - ключи целые числа, значения списки с целыми числами.
Нужно объединить списки из словаря и вернуть список списков, чтобы длинна вложенного списка не превышала 4000, нельзя "разрывать" список словаря.

Вопрос в том как сделать это красиво? Реализация которая у меня получилась мне не нравится...
@staticmethod
    def group_by_part_limit(tickets: t.Dict[int, list[int]]) -> t.List[t.List[int]]:
        DEFAULT_PART_LIMIT = 4000
        parts: list[list[int]] = []
        while tickets:
            part_tickets: list[int] = []
            for house in list(tickets):
                if len(part_tickets) + len(tickets.get(house)) < DEFAULT_PART_LIMIT:
                    part_tickets.extend(tickets.pop(house))
                else:
                    break
            parts.append(part_tickets)
        return parts


Тест
@mark.parametrize(
    'tickets, expected, part_count', [
        ({1: [1, 2, 3], 2: [4, 5, 6]}, [[1, 2, 3, 4, 5, 6]], 1),
        ({1: [i for i in range(1, 901)], 2: [i for i in range(901, 1801)], 3: [i for i in range(1801, 2701)], 
          4: [i for i in range(2701, 3601)], 5: [i for i in range(3601, 4501)]}, 
          [[i for i in range(1, 3601)],  [i for i in range(3601, 4501)]], 2),
    ]
)
async def test_group_by_part_limit(tickets: dict[int, list[int]], expected: list[list[int]], part_count: int):
    result = SubTaskControl.group_by_part_limit(tickets)
    assert_that(len(result), is_(part_count))
    assert_that(result, is_(expected))
  • Вопрос задан
  • 200 просмотров
Решения вопроса 1
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
В коментариях указали, что списки можно переставлять.

Это известная, очень сложная (NP-сложная) задача об упаковке.

Для сотен тысяч входных списков вы оптимальное по количеству кусков в ответе решение не найдете за все время до тепловой смерти вселенной. Всякие аппроксимации, вроде вашего жадного алгоритма, могут найти лишь какое-то хорошее, но не лучшее разбиение. В частности, у вас используется Next-Fit аппроксимация - вы в итоге можете выдать в 2 раза больше кусков в ответе, чем можно было бы. Есть более сложные алгоритмы, которые, например, гарантируют ухудшение максимум в 1.7 раза.

Соглашусь с Dr. Bacon, через yield код вашего решения может быть чуть красивее, но я не совсем понимаю, что в вашей реализации вам так "не красиво". Хотя я не питонист.

Далее, вы упоминули, что ключи во входных данных - это номера домов, а числа в списках - номера квартир. Вы как-то объединяете дома с ограничением на количество квартир. Не знаю, что у вас за задача на самом деле, но мне кажется логичным, что вам надо бы объединять дома только рядом. С одной улицы, или вообще идущие подряд. Ведь если в одной группе идут квартиры из домов в разных концах города, то какая вообще разница, что квартиры из одного дома могут быть в разных группах? Если такое ограничение ввести, то задача упрощается и ваше решение будет оптимальным.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы