Стрельба 2 анализ
Créé le : 30 décembre 2024
Créé le : 30 décembre 2024
Коля играет в одну простую игру под названием «Стрельба 2». Игра заключается в следующем – есть персонаж, который передвигается в плоском мире со скоростью М клеток в секунду и умеет стрелять из пистолета. Первоначально персонаж начинает движение с координаты 0 (двигаясь по одномерной оси) и имеет пистолет, который может достигать цели при стрельбе с расстояния K клетки, притом производя по U выстрелов в секунду, наносящих по 1 единицы урона. Также заранее известны координаты всех препятствий и их очки здоровья (ОЗ). Также на оси есть туманные области, которые не являются препятствиями, но стрельба через них понижает атаку персонажа в 2 раза нацело (если выстрел наносил 1 единицу урона, то будет 0; если 2, то 1; если 3, то 1; и т.д.).
Помогите Коле определить расстояние, которое пройдёт его персонаж по заданным входным параметрам.
Входные данные:
На вход на первой строке подаётся целое число L (1 <= L <= 100000) – длина оси, по которой будет передвигаться персонаж, целое число K (1 <= K <= L), целое число U (1 <= U <= 1000), целое число М (1<=М<=1000).
На второй строке подаётся целое число N (1 <= N <= 1000) – количество разрушаемых препятствий на оси.
Далее на N строках подаются целые координаты препятствий (целое число от 1 до L-1) и их ОЗ через пробел (например, 5 2, на координате 5 стоит препятствие с 2 ОЗ).
После на новой строке подаётся целое число D (1 <= D <= 1000) – количество туманных областей на оси.
Далее на D-строках подаются целые координаты тумана на оси (одно число от 1 до L-1).
Выходные данные:
На выходе требуется вывести одно целое число – расстояние, которое пройдёт персонаж.
Примечания.
Если персонаж проходит весь маршрут, то вывести L.
Когда персонаж не доходит до конца (упирается в препятствие, которое не успел уничтожить), то считается, что он прошёл ровно такое расстояние, на координате которой стояло препятствие (если персонаж закончил игру на препятствии по координате 9, то считается, что он прошёл 9 клеток).
Если при стрельбе пуля пролетает больше чем через одну туманную область, то считаем, что на её урон влияет только первая.
Персонаж каждую секунду останавливается и производит U выстрелов, если выстрел уничтожает цель и остались ещё выстрелы, которые могут долететь до следующего препятствия, то ему наносится урон.
Пример:
Входные данные
Выходные данные
15 3 1 1
3
3 3
5 2
9 6
1
4
5
Рассмотрим пример
Персонаж начинает с координаты 0, на расстоянии 3 есть препятствие с 3 ОЗ.
Персонаж сразу же может начать стрелять, так как расстояние K=3.
Придя на координату 3 – это препятствие будет уничтожено.
Далее есть препятствие по координате 5, но оно за туманом по координате 4, поэтому урон при стрельбе через него понижается нацело на 2 (1 единица урона становится равной 0). Прежний урон (1 ОЗ за выстрел) вернётся только после прохождения тумана (на координате 4). Но уничтожить препятствие он не успеет, так как требуется произвести 2 выстрела, а стреляет он раз в секунду, поэтому, игра закончится на расстоянии 5.
Чтобы решить эту задачу, необходимо смоделировать движение персонажа и его атаки по заданным правилам. Ниже приведен подробный алгоритм решения, а также реализация на языке Python.
Ввод данных:
L
, дальность стрельбы K
, количество выстрелов в секунду U
и скорость M
.N
и сохранить их координаты и очки здоровья.D
и сохранить их координаты.Предварительная обработка:
Симуляция движения и стрельбы:
pos = 0
и время time = 0
.pos < L
:
K
клеток от текущей позиции.M
клеток вперед.L
без остановок, вывести L
.Учёт туманных областей:
pythondef main(): import sys import math import sys sys.setrecursionlimit(1 << 25) L, K, U, M = map(int, sys.stdin.readline().split()) N = int(sys.stdin.readline()) obstacles = {} obstacle_positions = [] for _ in range(N): coord, hp = map(int, sys.stdin.readline().split()) obstacles[coord] = hp obstacle_positions.append(coord) D = int(sys.stdin.readline()) fogs = set() for _ in range(D): fog = int(sys.stdin.readline()) fogs.add(fog) obstacle_positions.sort() pos = 0 time = 0 destroyed = set() while pos < L: # Стрельба # Найти все препятствия в пределах K клеток вперед targets = [coord for coord in obstacle_positions if pos < coord <= pos + K and coord not in destroyed] # Сортируем по расстоянию targets.sort() shots = U for target in targets: if shots == 0: break distance = target - pos # Определить, пересекает ли путь туман # Найти первый туман на пути от pos+1 до target first_fog = -1 for fog in range(pos + 1, target): if fog in fogs: first_fog = fog break if first_fog != -1: damage = 1 // 2 # Понижение урона нацело else: damage = 1 if damage == 0: continue # Урон не наносится obstacles[target] -= damage shots -= 1 if obstacles[target] <= 0: destroyed.add(target) # Проверить, достиг ли персонаж препятствия pos += M if pos > L: pos = L # Проверить, есть ли препятствие на текущей позиции if pos in obstacles and pos not in destroyed: print(pos) return time += 1 print(L) if __name__ == "__main__": main()
Чтение входных данных:
L
, K
, U
, M
.obstacles
для быстрого доступа по координате.fogs
.Сортировка препятствий:
obstacle_positions
для удобства обработки ближайших препятствий.Основной цикл симуляции:
pos < L
):
K
.M
клеток вперед.Завершение игры:
L
.Входные данные:
text15 3 1 1 3 3 3 5 2 9 6 1 4
Выходные данные:
5
Объяснение: Персонаж движется со скоростью 1 клетку в секунду. Он может стрелять с дальностью 3 клетки, делая 1 выстрел в секунду.
Таким образом, персонаж прошел 5 клеток.
Данная задача требует внимательного моделирования процесса движения и атаки персонажа с учетом всех условий, включая туманные области и скорость стрельбы. Представленный алгоритм и реализация позволяют эффективно определить расстояние, которое пройдет персонаж.
Маша учится в школе, но безумно любит посещать открытые лекции в МГТУ им. Н.Э. Баумана. Маша старается всегда использовать своё свободное время максимально продуктивно, потому она заранее скачивает расписание преподавателей, чтобы посетить по лекции минимум 50% преподавателей в день, которые она выбрала.
Преподаватели читают одну и ту же лекцию несколько раз в день, в разные промежутки времени. Но у преподавателей есть негласное правило – можно опоздать на лекцию не больше, чем на 5 минут от начала. Можно уйти с лекции на 5 минут раньше.
Но иногда преподаватели разбросаны по расписанию очень сильно, иногда их время пересекается с другими. Поэтому Маше нужна помощь, чтобы по входному расписанию преподавателей определить, во сколько ей нужно быть в университете, чтобы посетить лекции минимум 50% преподавателей (если преподавателей нечётное количество, то округляем вверх (1 округляется до 1, 3 до 2 и так далее), а также провести минимальное количество времени в ожидании между лекциями (если они не подряд).
Входные данные:
На первой строке подаётся целое число N (1 <= N <= 100) – количество преподавателей, на лекции которых хочет сходить Маша.
Далее подаётся N наборов строк в виде:
· на одной строке указывается количество занятий для i-го преподавателя N_i (1 <= N_i <= 50);
· на N_i строках далее указываются временные промежутки занятий преподавателя (без самопересечений) в виде hh:mm-hh:mm (например, 09:10-10:15).
Выходные данные
На первой строке выведите, в какое время начнётся первая пара, на которую придёт Маша.
На второй строке выведите общее количество в минутах, которое Маша проведёт на лекциях.
На третьей строке выведите общее количество в минутах, которое Маша проведёт между лекциями.
Примечание:
· для удобства расчёта считаем, что путь с одной лекции до другой не занимает времени;
· время лекции у одного преподавателя всегда одинаковое;
· гарантируется, что Маша сможет посетить лекцию минимум 50% преподавателей;
· если задача имеет несколько ответов, то вывести тот, при котором Маша приедет как можно раньше;
· Маша пытается приехать как можно раньше, поэтому, как только она посетит 50% преподавателей, то она может уезжать домой, но приоритетом в задаче является в первую очередь минимальное время проведённое в ожидании между занятиями.
Входные данные
Выходные данные
3
2
10:05-11:50
17:00-18:45
1
11:45-12:30
2
13:00-14:00
16:00-17:00
10:05
145
0
Маше требуется посетить лекции 50% преподавателей, поэтому достаточно посетить 2 преподавателей. Маша пытается найти самое минимальное время для ожидания между занятиями. В данном случае возможны два варианта, когда Маша проведёт между занятиями 0 минут времени:
· посетив лекцию третьего преподавателя 16:00-17:00 и первого 17:00-18:45;
· посетив лекцию первого преподавателя 10:05-11:50 и второго 11:45-12:30.
Так как время ожидания между лекциями одинаковое, то выбираем тот вариант, при котором Маша приедет как можно раньше – 10:05.
Чтобы решить эту задачу, необходимо эффективно выбрать набор лекций от различных преподавателей, удовлетворяющий следующим условиям:
Количество преподавателей: Маша должна посетить как минимум 50% преподавателей, округляя вверх (то есть ceil(N/2)
).
Временные ограничения: Маша может прибыть на лекцию не более чем на 5 минут позже её начала и может уйти не более чем за 5 минут до её окончания.
Минимизация времени ожидания: Если Маша посещает несколько лекций подряд, необходимо минимизировать общее время ожидания между ними.
Приоритет: Если существует несколько вариантов с одинаковым временем ожидания, выбрать тот, где Маша прибывает в университет как можно раньше.
Предобработка данных:
hh:mm
в минуты с начала дня (от 00:00 до 23:59), чтобы упростить сравнение и расчёты.Выбор преподавателей:
ceil(N/2)
преподавателей, необходимо выбрать комбинацию лекций, удовлетворяющую условиям.Поиск оптимального набора лекций:
ceil(N/2)
преподавателей выбираем одну лекцию от каждого.Оптимизация:
N <= 100
, N_i <= 50
).Однако, учитывая, что N
может быть до 100, полный перебор всех комбинаций является вычислительно неэффективным. Поэтому мы применим жадный подход, выбирая лекции таким образом, чтобы минимизировать время ожидания и выбрать максимально раннее время начала.
Ниже приведён код на языке Python, который реализует описанный подход. Для упрощения и ускорения работы алгоритма мы используем сортировку лекций и жадный выбор оптимального набора лекций.
pythonimport sys import math from itertools import combinations from collections import defaultdict def time_to_minutes(t): """Преобразование времени из формата 'hh:mm' в минуты с начала дня.""" hours, minutes = map(int, t.split(':')) return hours * 60 + minutes def parse_time_interval(interval): """Преобразование временного интервала из строки в пару минут.""" start, end = interval.split('-') return (time_to_minutes(start), time_to_minutes(end)) def main(): import sys # Чтение входных данных input = sys.stdin.read().splitlines() idx = 0 N = int(input[idx]); idx += 1 # Количество преподавателей professors = [] for _ in range(N): Ni = int(input[idx]); idx += 1 # Количество лекций для i-го преподавателя lectures = [] for _ in range(Ni): interval = input[idx]; idx +=1 lectures.append(parse_time_interval(interval)) professors.append(lectures) # Определение количества преподавателей, которых необходимо посетить required = math.ceil(N / 2) # Создание списка всех лекций с указанием преподавателя all_lectures = [] for prof_id, lectures in enumerate(professors): for lecture in lectures: all_lectures.append((lecture[0], lecture[1], prof_id)) # Сортировка лекций по времени начала all_lectures.sort() # Инициализация переменных для хранения оптимального решения best_start = None best_total_time = None best_waiting_time = None # Используем жадный подход: пытаемся начать как можно раньше и добавлять лекции с минимальными ожиданиями # Для каждого возможного набора преподавателей, выберем одну лекцию и проверим совместимость # Однако, полный перебор невозможен из-за большого числа комбинаций, поэтому применим эвристический метод # Группируем лекции по преподавателям lectures_per_prof = defaultdict(list) for lec in all_lectures: lectures_per_prof[lec[2]].append((lec[0], lec[1])) # Выбираем всех возможных комбинаций из required преподавателей # Но даже при N=100, required=50, это невозможно. Поэтому применим другой подход. # Вместо перебора всех комбинаций, выберем лекции в порядке их начала и постараемся собрать требуемое количество # с учётом условий. # Сортируем все лекции по началу all_lectures_sorted = sorted(all_lectures, key=lambda x: x[0]) # Будем хранить для каждой лекции, сколько преподавателей уже включено, и соответствующие параметры from bisect import bisect_left, bisect_right # Инициализируем переменные для отслеживания лучших результатов optimal_start = None optimal_total_time = None optimal_waiting_time = None # Поскольку N и N_i большие, полный перебор невозможен. Поэтому применим следующий подход: # Для каждого лекции, попробуем построить расписание, начиная с этой лекции. for lec in all_lectures_sorted: start_time, end_time, prof_id = lec # Начинаем с этой лекции selected_profs = set([prof_id]) current_start = start_time current_end = end_time total_time = end_time - start_time waiting_time = 0 # Используем список для хранения текущих расписаний schedule = [(start_time, end_time, prof_id)] # Ищем следующие лекции, которые не конфликтуют for next_lec in all_lectures_sorted: next_start, next_end, next_prof = next_lec if next_prof in selected_profs: continue # Проверяем, можно ли добавить эту лекцию после текущей # Учитываем, что Маша может уйти за 5 минут раньше и прийти на лекцию не более чем на 5 минут позже # То есть, следующий лекции должно начаться не раньше, чем (current_end - 5) и не позднее, чем (current_end + 5) # Однако, если лекция начинается раньше, то это не подходит # Для упрощения, определим, что лекция может быть добавлена, если она начинается не раньше, чем (current_end - 5) # и не позже, чем (current_end + 5) # Однако, в примере Маша может уйти за 5 минут раньше и прибыть на лекцию за 5 минут после начала # То есть, если предыдущая лекция заканчивается в T, она может покинуть её в T -5 # И прибыть на следующую лекцию в [start_next -5, start_next +5] # То есть, чтобы они совпадали, должна выполняться: # T -5 <= start_next +5 и T -5 + M <= start_next -5 # Возможно, проще учесть, что лекция должна начинаться не позже, чем предыдущая закончилась +10 # И не раньше, чем предыдущая закончилась -5 # Более точные условия: # Маша может уйти с предыдущей лекции в T_prev_leave = previous_end -5 # И прибыть на следующую лекцию в T_next_arrive = next_start +5 # Для того чтобы пересечение возможно: # T_prev_leave <= next_start +5 # И T_prev_leave >= next_start -5 # Однако, учитывая отсутствие времени на перемещение, проще рассмотреть, что лекция может начинаться не позже, чем T_prev_leave + 10 # И не раньше, чем T_prev_leave - 5 # Для упрощения, допустим, что Маша может начать новую лекцию не раньше, чем предыдущая закончилась -5 # и не позже, чем предыдущая закончилась +5 # Таким образом, условие: if next_start <= current_end + 5 and next_start >= current_end - 5: # Можно добавить эту лекцию selected_profs.add(next_prof) # Обновляем время new_start = min(current_start, next_start) new_end = max(current_end, next_end) # Обновляем общее время new_total_time = new_end - new_start # Обновляем время ожидания # В данном случае, ожидание между лекциями минимально, так как они пересекаются или почти пересекаются # Поэтому добавляем 0 или небольшой интервал # Для упрощения, считаем, что ожидание между лекциями равно next_start - current_end wait = max(0, next_start - current_end) new_waiting_time = waiting_time + wait # Обновляем текущие значения current_start = new_start current_end = new_end total_time = new_total_time waiting_time = new_waiting_time schedule.append((next_start, next_end, next_prof)) # Проверяем, достигли ли мы требуемого количества преподавателей if len(selected_profs) == required: break # После построения расписания, проверяем, достигли ли мы требуемого количества преподавателей if len(selected_profs) >= required: # Вычисляем общее время, проведённое в университете total_time_spent = current_end - current_start # Время ожидания уже учтено # Сравниваем с текущим лучшим решением if best_start is None or current_start < best_start or (current_start == best_start and waiting_time < best_waiting_time): best_start = current_start best_total_time = total_time_spent best_waiting_time = waiting_time elif current_start == best_start and waiting_time == best_waiting_time: if total_time_spent < best_total_time: best_total_time = total_time_spent best_waiting_time = waiting_time # Форматирование времени начала def minutes_to_time(m): hours = m // 60 minutes = m % 60 return f"{hours:02d}:{minutes:02d}" # Вывод результатов print(minutes_to_time(best_start)) print(best_total_time) print(best_waiting_time) if __name__ == "__main__": main()
Функции time_to_minutes
и parse_time_interval
:
hh:mm
в минуты с начала дня, что упрощает дальнейшие вычисления и сравнения.Чтение входных данных:
N
.N_i
и сами временные интервалы лекций.Подготовка данных:
all_lectures
, где каждая лекция представлена как кортеж (start_time, end_time, prof_id)
.Жадный выбор лекций:
required
).Форматирование и вывод результата:
hh:mm
.Временная эффективность: Данный подход может быть не оптимальным для больших значений N
и N_i
, так как он не рассматривает все возможные комбинации лекций. Для более эффективного решения можно использовать динамическое программирование или продвинутые алгоритмы графового поиска.
Точность условий: В текущей реализации условия по времени могут быть упрощены. Для более точного соблюдения правил допуска отклонений во времени (прибытие и уход) необходимо более тщательно обрабатывать временные интервалы.
Обработка пересечений: В случае, если лекции перекрываются, важно корректно рассчитывать общее время и время ожидания. В текущей реализации это учтено частично, но может потребовать дополнительной обработки.
Рассмотрим приведённый в задаче пример:
Входные данные:
text3 2 10:05-11:50 17:00-18:45 1 11:45-12:30 2 13:00-14:00 16:00-17:00
Выходные данные:
text10:05 145 0
Пояснение:
Таким образом, алгоритм корректно выбирает оптимальное расписание.
Данная задача требует внимательного подхода к обработке временных интервалов и выбору оптимального набора лекций. Представленный алгоритм использует жадный подход для выбора лекций, что позволяет эффективно найти решение при заданных ограничениях. Однако для более крупных входных данных может потребоваться более сложный алгоритм с улучшенной временной эффективностью.