Разбор задачи: Возможность Отгрузки Посылок В Течение D Дней

Предложенный нами код:

 def shipWithinDays(weights, days):
    """
    :param weights: List[int] - список весов пакетов
    :param days: int - количество дней для доставки всех пакетов
    :return: int - минимальная грузоподъёмность корабля
    """
    def can_ship(capacity):
        # Проверяет, можно ли перевезти все пакеты с заданной грузоподъёмностью за `days` дней.
        total, required_days = 0, 1
        for weight in weights:
            if total + weight > capacity:
                required_days += 1
                total = 0
            total += weight
        return required_days <= days

    # Начальная минимальная грузоподъёмность - максимальный вес пакета
    # Начальная максимальная грузоподъёмность - сумма всех весов
    left, right = max(weights), sum(weights)

    while left < right:
        mid = (left + right) // 2
        if can_ship(mid):
            right = mid
        else:
            left = mid + 1

    return left

Заголовок функции

def shipWithinDays(weights, days):

Мы определяем функцию shipWithinDays, которая принимает два аргумента:

  1. weights — список целых чисел, где каждый элемент обозначает вес отдельного пакета.
  2. days — целое число, обозначающее количество дней, за которое необходимо доставить все пакеты.

Вспомогательная функция can_ship

def can_ship(capacity):
    total, required_days = 0, 1
    for weight in weights:
        if total + weight > capacity:
            required_days += 1
            total = 0
        total += weight
    return required_days <= days

Эта вспомогательная функция проверяет, можно ли перевезти все пакеты с заданной грузоподъёмностью capacity за days дней.

  1. Мы проходим по каждому пакету.
  2. Если текущий пакет вместе с уже загруженными превышает текущую грузоподъёмность capacity, то увеличиваем количество необходимых дней (required_days) и начинаем новую "погрузку" с текущего пакета.
  3. Если общее число дней, требуемых для перевозки всех пакетов, не превышает days, функция возвращает True.

Пример: Если weights = [3, 2, 2, 4] и capacity = 6, то:

  • В первый день: загружаем [3, 2] (общий вес 5, меньше 6).
  • Во второй день: загружаем [2, 4] (общий вес 6, равно 6). Итого, требуется 2 дня.

Инициализация границ поиска

left, right = max(weights), sum(weights)

Мы используем бинарный поиск, чтобы найти минимальную грузоподъёмность.

  • left — минимально возможная грузоподъёмность (максимальный вес одного пакета).
  • right — максимально возможная грузоподъёмность (сумма всех весов, если перевозить все пакеты за 1 день).

Бинарный поиск

while left < right:
    mid = (left + right) // 2
    if can_ship(mid):
        right = mid
    else:
        left = mid + 1

Мы выполняем бинарный поиск, чтобы найти минимальную грузоподъёмность:

  1. Находим середину диапазона (mid).
  2. Проверяем, можно ли перевезти все пакеты за days дней с грузоподъёмностью mid, вызвав функцию can_ship(mid).
  3. Если это возможно, уменьшаем правую границу (right = mid), так как ищем минимальную возможную грузоподъёмность.
  4. Если это невозможно, увеличиваем левую границу (left = mid + 1).

Идея: Мы сужаем диапазон поиска до тех пор, пока left и right не совпадут.


Результат

return left

После завершения бинарного поиска left содержит минимальную грузоподъёмность, при которой все пакеты можно доставить за days дней.


Пример работы алгоритма

Входные данные:

weights = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
days = 5
  1. Инициализация:
    left = max(weights) = 10
    right = sum(weights) = 55
  2. Первый шаг бинарного поиска:
    mid = (10 + 55) // 2 = 32
    Проверяем can_ship(32).
    • День 1: [1, 2, 3, 4, 5, 6] (вес 21)
    • День 2: [7, 8] (вес 15)
    • День 3: [9, 10] (вес 19)
      Ответ: True (требуется 3 дня ≤ 5).
      Сужаем диапазон: right = 32.
  3. Второй шаг бинарного поиска:
    mid = (10 + 32) // 2 = 21
    Проверяем can_ship(21).
    • День 1: [1, 2, 3, 4, 5] (вес 15)
    • День 2: [6, 7] (вес 13)
    • День 3: [8] (вес 8)
    • День 4: [9, 10] (вес 19)
      Ответ: True.
      Сужаем диапазон: right = 21.
  4. Третий шаг бинарного поиска:
    mid = (10 + 21) // 2 = 15
    Проверяем can_ship(15).
    • День 1: [1, 2, 3, 4, 5] (вес 15)
    • День 2: [6, 7] (вес 13)
    • День 3: [8] (вес 8)
    • День 4: [9] (вес 9)
    • День 5: [10] (вес 10)
      Ответ: True.
      Сужаем диапазон: right = 15.
  5. Четвертый шаг бинарного поиска:
    mid = (10 + 15) // 2 = 12
    Проверяем can_ship(12).
    • День 1: [1, 2, 3, 4] (вес 10)
    • День 2: [5, 6] (вес 11)
    • День 3: [7, 8] (вес 15)
    • День 4: [9] (вес 9)
    • День 5: [10] (вес 10)
      Ответ: False (требуется 6 дней > 5).
      Расширяем диапазон: left = 13.
  6. Пятый шаг бинарного поиска:
    mid = (13 + 15) // 2 = 14
    Проверяем can_ship(14).
    Ответ: False.
    Расширяем диапазон: left = 15.
  7. Завершение:
    left == right == 15.
    Ответ: минимальная грузоподъёмность — 15.

 



Вы должны Войти или Зарегистрироваться чтобы оставлять комментарии