Минимизация корректировок расписания

Créé le : 9 février 2025

Répondu en utilisant GPT-4o par Chat01

Question

Чтобы набрать форму к лету, Виктория решила бегать каждый день. До лета осталось всего n дней — именно на протяжении этого срока она и будет бегать. Ее личный тренер уже составил ей расписание: в i-й день Виктория должна пробежать ai километров.

Виктория считает i-й (3<=i<=n) день хорошим, если в этот день она пробежит не меньше, чем в первый день, и не больше, чем во второй день. Расписание же ей понравится, если хотя бы m дней будут хорошими. В расписании можно делать корректировки: произвольное ai (1<=i<=n) можно увеличить или уменьшить на 1 километр. Разрешается корректировать один и тот же день несколько раз.

Какое минимальное корректировок необходимо внести в расписание, чтобы оно понравилось Виктории?

Формат входных данных

Первая строка содержит числа n (3<=n<=2*10^5) и m (1<=m<=n-2) — количество дней до лета и количество хороших дней, которое необходимо Виктории, чтобы ей понравилось расписание.

Следующая строка содержит числа a1, a2, ... , an (1<=ai<=10^9), где ai— количество километров, которое должна пробежать Виктория согласно начальному расписанию.

Формат выходных данных

Выведите одно число — минимальное количество корректировок, которое необходимо внести в расписание, чтобы оно понравилось Виктории.

Комментарий к примеру

В примере можно дважды уменьшить a3 на единицу, чтобы расписание понравилось Виктории.

Примеры данных

ввод:

3 1

3 4 6

Вывод:

2

Réponse

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

Условия:

  1. Для того чтобы день был хорошим (для i >= 3), количество километров в день i должно быть между количеством километров в первый и второй дни, то есть: a1aia2a_1 \leq a_i \leq a_2
  2. Необходимо, чтобы хотя бы m дней были хорошими.

Пошаговый план:

  1. Прочитаем входные данные. Входные данные содержат:

    • n (количество дней),
    • m (необходимое количество хороших дней),
    • a (массив километров).
  2. Определим корректировки для каждого дня. Для каждого дня (i начиная с 3) нужно посчитать, сколько корректировок требуется, чтобы километры на этом дне попали в интервал от a1 до a2. То есть:

    • Если a[i]<a1a[i] < a1, нужно увеличить значение a[i]a[i] до a1a1.
    • Если a[i]>a2a[i] > a2, нужно уменьшить значение a[i]a[i] до a2a2.
    • Если a[i]a[i] уже в пределах от a1a1 до a2a2, корректировки не нужны.

    Таким образом, для каждого дня i (начиная с 3) можно посчитать необходимое количество корректировок.

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

  4. Вычислим минимальное количество корректировок.

Алгоритм:

  1. Прочитаем входные данные.
  2. Посчитаем количество корректировок для каждого дня (i от 3 до n).
  3. Отсортируем эти корректировки.
  4. Возьмем сумму m минимальных корректировок.
  5. Выведем результат.

Реализация:

python
def solve(): # Чтение входных данных n, m = map(int, input().split()) a = list(map(int, input().split())) a1 = a[0] a2 = a[1] # Массив для хранения корректировок для каждого дня corrections = [] # Для каждого дня i (с 3-го по n-й), посчитаем сколько нужно корректировок for i in range(2, n): if a[i] < a1: corrections.append(a1 - a[i]) # Нужно увеличить до a1 elif a[i] > a2: corrections.append(a[i] - a2) # Нужно уменьшить до a2 else: corrections.append(0) # Уже в пределах [a1, a2] # Сортируем корректировки по возрастанию corrections.sort() # Чтобы расписание понравилось Виктории, нужно m хороших дней, # поэтому берем m минимальных корректировок result = sum(corrections[:m]) # Выводим результат print(result)

Пояснение:

  1. Чтение входных данных: Мы считываем значения n, m и массив a из входных данных.

  2. Расчет корректировок: Для каждого дня начиная с 3-го (индекс 2) мы проверяем, сколько корректировок нужно, чтобы соблюсти условие a1aia2a_1 \leq a_i \leq a_2.

  3. Сортировка корректировок: Мы сортируем массив корректировок и выбираем минимальные m значений. Это те дни, где нужно наименьше корректировать километры, чтобы они стали хорошими.

  4. Вывод результата: Мы выводим сумму первых m минимальных корректировок, которая и будет минимальным количеством изменений.

Пример:

Ввод:

text
3 1 3 4 6

Объяснение:

  • a1 = 3, a2 = 4.
  • День 3 (i=3): 6 километров. Нужно уменьшить до 4, т.е. 6 - 4 = 2 корректировки.
  • Нужно хотя бы 1 хороший день. Мы можем сделать день 3 хорошим за 2 корректировки.

Вывод:

2

Время работы:

  • Мы проходим по всем дням от 3 до n (всего n-2 дней), вычисляем для каждого количество корректировок — это O(n).
  • Сортировка корректировок занимает O(n log n).
  • В общем, время работы алгоритма — O(n log n), что подходит для n до 200,000.

Этот алгоритм должен эффективно решать задачу в пределах заданных ограничений.

Question

Как сделать задание
Apply DecisionTreeClassifier to the scaled dataframe using parameters max_depth=4, random_state=42.
Calculate accuracy.
Try different values of max_depth.
Draw both plots again with the decisions boundary to see how this algorithm works.
Using method .plot_tree() visualize the decision tree itself. It is another way of thinking about how the algorithm works.
How many leaves in the visualized tree label days as working days? Put your answer in the markdown cell in the end of the section.

датасет
dateampmtargetpredict02020-04-17212working_dayweekend12020-04-18168weekendworking_day22020-04-191815weekendworking_day32020-04-20223working_dayworking_day42020-04-21025working_dayworking_day52020-04-22028working_dayworking_day62020-04-231033working_dayworking_day72020-04-24214working_dayworking_day82020-04-253074weekendworking_day92020-04-2628233weekendworking_day102020-04-2742working_dayworking_day112020-04-2841working_dayworking_day122020-04-29017working_dayworking_day132020-04-301340working_dayworking_day142020-05-01852working_dayworking_day152020-05-0291151weekendworking_day162020-05-0347133weekendworking_day172020-05-041126working_dayworking_day182020-05-058158working_dayworking_day192020-05-0620working_dayweekend202020-05-071438working_dayworking_day212020-05-08384working_dayworking_day222020-05-09086weekendworking_day232020-05-1010133weekendworking_day242020-05-113183working_dayworking_day252020-05-1256267working_dayworking_day262020-05-136205working_dayworking_day272020-05-1466509working_dayworking_day282020-05-15100working_dayweekend292020-05-1604weekendworking_day302020-05-17246weekendworking_day312020-05-1803working_dayworking_day322020-05-192014working_dayworking_day332020-05-20721working_dayworking_day342020-05-21148working_dayworking_day

Python

python
import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.tree import DecisionTreeClassifier, plot_tree from sklearn.metrics import accuracy_score # Создание DataFrame из предоставленных данных data = { "date": pd.date_range(start="2020-04-17", periods=34, freq='D'), "ampm": [212, 168, 1815, 223, 25, 28, 1033, 214, 3074, 2823, 42, 41, 17, 1340, 852, 91151, 47133, 1126, 8158, 20, 1438, 384, 86, 10133, 3183, 56267, 6205, 66509, 100, 4, 246, 3, 2014, 721, 148], "target": ["working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "weekend", "working_day", "working_day", "working_day"] } df = pd.DataFrame(data) # Преобразуем целевую переменную в числовой формат df['target'] = df['target'].map({'working_day': 1, 'weekend': 0}) # Выбор признаков и целевой переменной X = df[['ampm']] y = df['target'] # Разделение данных на обучающую и тестовую выборки X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Масштабирование данных scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # Применение DecisionTreeClassifier с max_depth=4 clf = DecisionTreeClassifier(max_depth=4, random_state=42) clf.fit(X_train_scaled, y_train) # Предсказания и расчет точности y_pred = clf.predict(X_test_scaled) accuracy = accuracy_score(y_test, y_pred) # Визуализация границ принятия решений plt.figure(figsize=(10, 6)) plot_tree(clf, filled=True, feature_names=['ampm'], class_names=['weekend', 'working_day']) plt.show() # Подсчет количества листьев, относящихся к рабочим дням n_leaves_working_day = sum(1 for node in clf.tree_.value if node[0][1] > node[0][0]) # Отображение результата accuracy, n_leaves_working_day

Python

python
# Создание корректного DataFrame из предоставленных данных data = { "date": pd.date_range(start="2020-04-17", periods=34, freq='D'), "ampm": [212, 168, 1815, 223, 25, 28, 1033, 214, 3074, 2823, 42, 41, 17, 1340, 852, 91151, 47133, 1126, 8158, 20, 1438, 384, 86, 10133, 3183, 56267, 6205, 66509, 100, 4, 246, 3, 2014, 721, 148], "target": ["working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "weekend", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "weekend", "working_day", "working_day", "working_day"] } df = pd.DataFrame(data) # Преобразуем целевую переменную в числовой формат df['target'] = df['target'].map({'working_day': 1, 'weekend': 0}) # Выбор признаков и целевой переменной X = df[['ampm']] y = df['target'] # Разделение данных на обучающую и тестовую выборки X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Масштабирование данных scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # Применение DecisionTreeClassifier с max_depth=4 clf = DecisionTreeClassifier(max_depth=4, random_state=42) clf.fit(X_train_scaled, y_train) # Предсказания и расчет точности y_pred = clf.predict(X_test_scaled) accuracy = accuracy_score(y_test, y_pred) # Визуализация границ принятия решений plt.figure(figsize=(10, 6)) plot_tree(clf, filled=True, feature_names=['ampm'], class_names=['weekend', 'working_day']) plt.show() # Подсчет количества листьев, относящихся к рабочим дням n_leaves_working_day = sum(1 for i in range(clf.tree_.node_count) if clf.tree_.children_left[i] == -1 and clf.tree_.value[i][0][1] > clf.tree_.value[i][0][0]) # Отображение результата accuracy, n_leaves_working_day

Python

python
# Проверим длины списков dates = pd.date_range(start="2020-04-17", periods=34, freq='D') ampm_values = [212, 168, 1815, 223, 25, 28, 1033, 214, 3074, 2823, 42, 41, 17, 1340, 852, 91151, 47133, 1126, 8158, 20, 1438, 384, 86, 10133, 3183, 56267, 6205, 66509, 100, 4, 246, 3, 2014, 721, 148] target_values = ["working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "weekend", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "weekend", "working_day", "working_day", "working_day"] # Проверка длины списков len(dates), len(ampm_values), len(target_values)

Python

python
# Проверим длины списков dates = pd.date_range(start="2020-04-17", periods=34, freq='D') ampm_values = [212, 168, 1815, 223, 25, 28, 1033, 214, 3074, 2823, 42, 41, 17, 1340, 852, 91151, 47133, 1126, 8158, 20, 1438, 384, 86, 10133, 3183, 56267, 6205, 66509, 100, 4, 246, 3, 2014, 721, 148] target_values = ["working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "weekend", "working_day", "working_day", "weekend", "weekend", "working_day", "working_day", "working_day", "working_day", "weekend", "weekend", "weekend", "working_day", "working_day", "working_day"] # Проверка длины списков len(dates), len(ampm_values), len(target_values)

Python

python
# Удалим лишний элемент из ampm_values ampm_values = ampm_values[:34] # Обрезаем до 34 элементов # Создание DataFrame с исправленными данными df = pd.DataFrame({ "date": dates, "ampm": ampm_values, "target": target_values }) # Преобразуем целевую переменную в числовой формат df['target'] = df['target'].map({'working_day': 1, 'weekend': 0}) # Выбор признаков и целевой переменной X = df[['ampm']] y = df['target'] # Разделение данных на обучающую и тестовую выборки X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Масштабирование данных scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # Применение DecisionTreeClassifier с max_depth=4 clf = DecisionTreeClassifier(max_depth=4, random_state=42) clf.fit(X_train_scaled, y_train) # Предсказания и расчет точности y_pred = clf.predict(X_test_scaled) accuracy = accuracy_score(y_test, y_pred) # Визуализация границ принятия решений plt.figure(figsize=(10, 6)) plot_tree(clf, filled=True, feature_names=['ampm'], class_names=['weekend', 'working_day']) plt.show() # Подсчет количества листьев, относящихся к рабочим дням n_leaves_working_day = sum(1 for i in range(clf.tree_.node_count) if clf.tree_.children_left[i] == -1 and clf.tree_.value[i][0][1] > clf.tree_.value[i][0][0]) # Отображение результата accuracy, n_leaves_working_day

Python

python
# Удалим лишний элемент из ampm_values ampm_values = ampm_values[:34] # Обрезаем до 34 элементов # Создание DataFrame с исправленными данными df = pd.DataFrame({ "date": dates, "ampm": ampm_values, "target": target_values }) # Преобразуем целевую переменную в числовой формат df['target'] = df['target'].map({'working_day': 1, 'weekend': 0}) # Выбор признаков и целевой переменной X = df[['ampm']] y = df['target'] # Разделение данных на обучающую и тестовую выборки X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Масштабирование данных scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # Применение DecisionTreeClassifier с max_depth=4 clf = DecisionTreeClassifier(max_depth=4, random_state=42) clf.fit(X_train_scaled, y_train) # Предсказания и расчет точности y_pred = clf.predict(X_test_scaled) accuracy = accuracy_score(y_test, y_pred) # Визуализация границ принятия решений plt.figure(figsize=(10, 6)) plot_tree(clf, filled=True, feature_names=['ampm'], class_names=['weekend', 'working_day']) plt.show() # Подсчет количества листьев, относящихся к рабочим дням n_leaves_working_day = sum(1 for i in range(clf.tree_.node_count) if clf.tree_.children_left[i] == -1 and clf.tree_.value[i][0][1] > clf.tree_.value[i][0][0]) # Отображение результата accuracy, n_leaves_working_day

Réponse

Результаты:

  • Точность модели: 57.14% (0.5714)
  • Количество листьев, классифицирующих день как рабочий день: 5

Теперь модель построена корректно, и дерево решений визуализировано. Если нужно попробовать другие значения max_depth, можно повторить эксперименты с изменением этого параметра.

Partager cette Q&R