Решение задачи #5. Python Яндекс CodeRun, Кафе

Опубликовано: 22.02.2025, 20:55 | Автор: hdhAI

Вариант решения задачи на языке программирования Python с Яндекс CodeRun.
Категория: Алгоритмы.
Название задачи: Кафе.
Статус решения: "Решено".

Условие задачи:
Около Петиного университета недавно открылось новое кафе, в котором действует следующая система скидок: при каждой покупке более чем на 100 рублей покупатель получает купон, дающий право на один бесплатный обед (при покупке на сумму 100 рублей и меньше такой купон покупатель не получает).

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

Формат ввода:
В первой строке входного файла записано целое число N (0 ≤≤ N ≤≤ 100). В каждой из последующих N строк записано одно целое число, обозначающее стоимость обеда в рублях на соответствующий день. Стоимость — неотрицательное целое число, не превосходящее 300.

Формат вывода:
В первой строке выдайте минимальную возможную суммарную стоимость обедов. Во второй строке выдайте два числа K1K1​ и K2K2​ — количество купонов, которые останутся неиспользованными у Пети после этих N дней и количество использованных им купонов соответственно.

В последующих K2K2​ строках выдайте в возрастающем порядке номера дней, когда Пете следует воспользоваться купонами. Если существует несколько решений с минимальной суммарной стоимостью, то выдайте то из них, в котором значение K1K1​ максимально (на случай, если Петя когда-нибудь ещё решит заглянуть в это кафе). Если таких решений несколько, выведите любое из них.

Решение:


Python

def main():
    import sys

    # Чтение входных данных
    N = int(input())  # Количество дней
    costs = [int(input()) for _ in range(N)]  # Стоимость обедов для каждого дня

    # Максимальное количество купонов ограничено числом дней
    max_coupons = N + 1  # На случай, если все дни дают купоны

    # dp[i][c] - минимальная стоимость за первые i дней с c оставшимися купонами
    dp = [[float('inf')] * max_coupons for _ in range(N + 1)]
    prev = [[None] * max_coupons for _ in range(N + 1)]  # Для восстановления пути

    # Начальное состояние: на нулевой день затраты равны 0, купонов нет
    dp[0][0] = 0

    # Заполнение таблицы динамики
    for i in range(1, N + 1):
        cost = costs[i - 1]
        for c in range(max_coupons):
            if dp[i - 1][c] == float('inf'):
                continue  # Если предыдущее состояние недостижимо, пропускаем

            # Вариант 1: Платим за обед (получаем купон, если цена > 100)
            new_coupons = c + (1 if cost > 100 else 0)
            if new_coupons < max_coupons and dp[i][new_coupons] > dp[i - 1][c] + cost:
                dp[i][new_coupons] = dp[i - 1][c] + cost
                prev[i][new_coupons] = (i - 1, c, False)  # Не использовали купон

            # Вариант 2: Используем купон (если есть хотя бы один)
            if c > 0 and dp[i][c - 1] > dp[i - 1][c]:
                dp[i][c - 1] = dp[i - 1][c]
                prev[i][c - 1] = (i - 1, c, True)  # Использовали купон

    # Поиск оптимального результата
    min_cost = float('inf')
    best_c = -1
    for c in range(max_coupons):
        if dp[N][c] < min_cost or (dp[N][c] == min_cost and c > best_c):
            min_cost = dp[N][c]
            best_c = c

    # Восстановление пути (номеров дней, когда использовались купоны)
    used_days = []
    i, c = N, best_c
    while i > 0:
        prev_i, prev_c, used_coupon = prev[i][c]
        if used_coupon:
            used_days.append(i)
        i, c = prev_i, prev_c

    # Вывод результатов
    print(min_cost)  # Минимальная суммарная стоимость
    print(best_c, len(used_days))  # Количество оставшихся и использованных купонов
    for day in sorted(used_days):  # Вывод дней в порядке возрастания
        print(day)


if __name__ == '__main__':
    main()

Объяснение кода


1. Чтение входных данных

Мы считываем количество дней N и список стоимостей обедов costs для каждого дня.
N — это число дней, а costs — массив из N элементов, где каждый элемент представляет стоимость обеда на соответствующий день.

2. Инициализация динамического программирования
Создаём двумерный массив dp, где dp[i][c] хранит минимальную сумму за первые i дней с c оставшимися купонами.
Создаём массив prev для отслеживания предыдущих состояний, чтобы можно было восстановить путь (какие дни были выбраны для использования купонов).

3. Заполнение таблицы динамики
Для каждого дня i и каждого возможного количества купонов c мы рассматриваем два варианта:
Вариант 1 : Платим за обед. Если стоимость обеда больше 100 рублей, получаем новый купон.
Вариант 2 : Используем купон, если он доступен (т.е., если c > 0).
Для каждого варианта обновляем значения в таблице dp и сохраняем информацию о предыдущем состоянии в массиве prev.

4. Поиск оптимального результата
После заполнения таблицы dp мы ищем минимальную стоимость среди всех возможных состояний на последнем дне (N).
Если несколько решений имеют одну и ту же минимальную стоимость, выбираем то, которое максимизирует количество оставшихся купонов (best_c).

5. Восстановление пути
Используя массив prev, восстанавливаем список дней, когда использовались купоны.
Результат хранится в списке used_days, который затем сортируется по возрастанию.

6. Вывод результатов
Сначала выводим минимальную сумму (min_cost).
Затем выводим количество оставшихся купонов (best_c) и количество использованных купонов (len(used_days)).
Наконец, выводим номера дней, когда использовались купоны, в порядке возрастания.

Пример работы программы:
Ввод:
5
35
40
101
59
63

Вывод:
235
0 1
5

Объяснение:
Минимальная сумма: 235 рублей.
Осталось 0 купонов, использован 1 купон.
Купон был использован в пятый день (день с индексом 5).

Детали реализации:
Сложность алгоритма :
Временная сложность: O(N2), так как мы перебираем все возможные состояния для каждого дня.
Пространственная сложность: O(N2), так как используем две таблицы размером N×(N+1).

Ограничения :
Код работает корректно при N≤100 и стоимости обедов до 300 рублей.

Обработка граничных случаев:
Если N=0, программа выведет 0 0 (нет дней, нет купонов).
Если все обеды стоят менее 100 рублей, купоны не будут получены.

Источник: hdhai.com

Похожие статьи
Интересное





Warning: file_put_contents(/var/www/angella1/data/www/hdhai.com/counter/count.php): Failed to open stream: Permission denied in /var/www/angella1/data/www/hdhai.com/counter.php on line 89