Научная статья на тему 'Разбор задач 25-го финала командного чемпионата мира ACM по программированию'

Разбор задач 25-го финала командного чемпионата мира ACM по программированию Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
178
19
i Надоели баннеры? Вы всегда можете отключить рекламу.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Елизаров Роман Анатольевич

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

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Разбор задач 25-го финала командного чемпионата мира ACM по программированию»

Елизаров Роман Анатольевич

РАЗБОР ЗАДАЧ 25-ГО ФИНАЛА КОМАНДНОГО ЧЕМПИОНАТА МИРА A CM ПО ПРОГРАММИРОВАНИЮ

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

Задача А. Конфигурация аэропорта. Из-за наличия магазинов и садов ко-

ридор нельзя пересечь по диагонали. Таким образом, расстояние между входом для прибывающих пассажиров в1 и входом для отбывающих пассажиров в3 (рисунок 1) равно 1 + 2 = 3.

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

«Авиалинии ACM» - это региональная авиакомпания, главным аэропортом которой является аэропорт Фон Неймана, через который проходит множество транзитных пассажиров. Аэропорт Фон Неймана представляет собой коридор. Входы для прибывающих пассажиров расположены на равном расстоянии друг от друга на северной стороне коридора. Входы для отбывающих пассажиров расположены на южной стороне коридора, также на равном расстоянии друг от друга. Расстояние между входами равно ширине коридора. Каждый вход для прибывающих пассажиров назначен в точности одному городу. То же верно и для отбывающих пассажиров. Каждый транзитный пассажир попадает в коридор через вход, назначенный для его города прибытия, и следует ко входу, назначенному для его города назначения. В этой задаче рассматриваются только транзитные пассажиры.

отбывающим парам входов.

Входные данные (файл ¿игрогип). Входной файл состоит из нескольких наборов тестовых данных. После

CL Cl О

СП G2 Ci

Arrival Gates

trl G2 G3

C.I f.i Cl

Departure Gates

Рисунок 1

последнего набора тестовых данных следует строка, содержащая число 0. Каждый набор тестовых данных состоит из двух частей: информация о транспортной нагрузке и конфигурационная секция.

Информация о нагрузке начинается с целого числа N (1 < N<25), представляющего собой число городов. Далее следуют N строчек, представляющих собой информацию о нагрузке для каждого города. Каждая строка информации о нагрузке начинается целым числом из диапазона 1..^ которое обозначает город отправления. После него следует целое число к и к пар целых чисел, по одной паре для каждого города назначения. Каждая пара определяет город назначения и число путешествующих по этому маршруту пассажиров (не более 500).

Конфигурационная секция состоит из некоторого числа (не более 20) конфигураций аэропорта и заканчивается строкой, содержащей число 0. Каждая конфигурация состоит из 3-х строк. Первая строка содержит положительное целое число, идентифицирующее конфигурацию. Следующая строка задает перестановку городов, как они назначены входам для прибывающих пассажиров: первое число представляет собой номер города, назначенного первому входу и т. д. Следующая строка таким же образом задает города, которые назначены входам для отбывающих пассажиров.

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

Для каждого набора входных данных выход представляет собой таблицу с номерами конфигураций и общей транспортной нагрузкой в порядке ее возрастания. Если две конфигурации имеют одинаковую нагрузку, то первой должна идти та, у которой меньший номер конфигурации. Придерживайтесь формата вывода, указанного в примере.

Пример.

Входной файл.

3

1 2 2 10 3 15

2 1 3 10

3 2 1 12 2 20 1

1 2 3

2 3 1 2

2 3 1

3 2 1 0

2

1 1 2 100 2 1 1 200 1 1 2 1 2 2 1 2 2 1 0 0

Вывод. Configuration Load 2 119

1 122 Configuration Load 2 300

1 600

Решение.

Решение этой задачи не представляет алгоритмической сложности, но требует некоторой аккуратности (программа представлена в приложении 1). На соревнованиях многие участники не могут решить задачи подобного рода с первой попытки из-за неверно прочитанного условия или пропуска каких-либо важных мелочей.

Будем хранить информацию о транспортной нагрузке в двухмерном массиве load (строка 14), в котором будет записано число путешествующих пассажиров между каждой парой городов (или 0, если оно не задано). Конфигурационную секцию будем хранить в двух одномерных массивах arrival и departure (строки 1819). Обратите внимание на необходимость очистки массива load перед загрузкой каждого набора данных (строка 28).

Общую нагрузку для каждой конфигурационной секции придется запоминать в отдельной структуре данных totals (строки 15-16), чтобы можно было выполнить сортировку перед выводом ответа на экран.

Обсчет каждой конфигурации и запоминание результатов в массиве totals производится в соответствии с условием задачи путем перебора всех пар входов для прибывающих и отбывающих пассажиров (строки 50-58). Вся процедура обсчета потребует время порядка O(C-N2), где C - количество конфигураций.

После обсчета всех конфигураций для текущего набора входных данных остается только отсортировать массив totals в соответствии с условием задачи и вывести ответ. Для такого небольшого количества элементов (по условию задачи есть не более 20 конфигураций в каждом наборе входных данных) прекрасно подойдет простейшая сортировка выбором (строки 60-70), что даст алгоритм с общим временем выполнения порядка O(C-N2+C2).

Задача E. Моллюски.

Исследователи запускают пару специально тренированных моллюсков в разных углах прямоугольного поля, разбитого на одинаковые квадратные клетки. Они ползут, разбрасывая светящиеся химикаты, присоединенные к их раковинам, в те клетки, через которые они проползают. Моллюски натренированы так, чтобы перемещаться на одну клетку за единицу времени, аппроксимируя заданный вектор. Если перемещение выводит моллюска за пределы поля, то тренированный дельфин мгновенно переносит его на противоположный край, обес- У печивая механизм «заворачивания». Перемещения моллюсков синхронизированы, однако моллюск останавливается после попадания в клетку, которую он уже посетил. Если два моллюска попадают в одну и ту же клетку, то они там останавливаются. Если два моллюска пытаются переместиться в клетки друг друга, то они также останавливаются.

Начальное положение моллюска таково, чтобы вектор его движения был направ-

10

лен «внутрь» поля. Оба моллюска начинают движение в момент времени £ = 1 в различных углах поля. Моллюск следует своему вектору так, как будто начальная точка вектора закреплена в центре клетки, из которой моллюск начал свое движение. Моллюск всегда передвигается в следующую клетку, которую вектор (или его продолжение) разбивает на части, за одним исключением: если вектор проходит через угол клетки, то моллюск перемещается сначала горизонтально, а затем вертикально для того, чтобы достичь следующей клетки, разделяемой вектором на части. На рисунках 2а, 2б показаны два примера движения моллюска (номера в клетках указывают прошедшее время). Координаты клеток отсчитываются, начиная с нуля, по осям х и у.

11

Рисунок 2а. Моллюск с вектором (-4,-3) перемещается по полю 6 на 5, начиная с клетки (5,4). В момент времени 12 он останавливается, так как заново попадает в клетку (5,4).

Рисунок 26. Моллюск с вектором (1,1) перемещается по полю 6 на 5, начиная с клетки (0,0). В момент времени 12 он останавливается, так как заново попадает в клетку (0,0).

Если бы оба моллюска на рисунке начали движение на одном и том же поле 6 на 5, то они остановились бы в момент времени 5, осветив в сумме 10 клеток.

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

Входные данные (файл £еоёиск.ш).

Входной файл состоит из набора тестовых данных, каждый из которых начинается со строки, содержащей два целых числа т и п - размеры поля по осям х и у, соответственно (1< т, п < 50), где т и п не могут быть оба равны 1. Вторая строка каждого набора содержит целое число к - количество моллюсков (2 < к < 10). Как минимум, одна пара моллюсков будет иметь различные начальные клетки. Следующие к строк содержат пары ненулевых целых чисел, представляющие собой компоненты х и у векторов направлений движения моллюсков. После последнего набора тестовых данных идет строка с двумя нулями.

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

Для каждого набора тестовых данных выведите его номер по порядку, максимальное количество клеток, которые можно осветить, минимально возможное время и номера всех пар моллюсков, которые достигают этих значений (максимального числа клеток за минимально возможное время). Порядок вывода не имеет значения, однако печатать одну и ту же пару два раза не нужно. Придерживайтесь формата вывода, указанного в примере.

Пример.

Входной файл.

6 5 3

-4 -3 1 1 1 -1 0 0

Вывод. Case 1

Cells Illuminated: 10 Minimum Time: 5

Geoduck IDs: 1 2

Geoduck IDs: 1 3

Решение.

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

Для моделирования перемещения каждого моллюска в отдельности удобно запоминать не только текущую координату моллюска на поле, но и вектор (Dx, Dy) на который моллюск переместился бы, если бы не было механизма «заворачивания». Рассмотрим моллюска, обе компоненты скорости (Vx, Vy) которого положительны, и решим задачу определения следующего перемещения этого моллюска - на одну клетку вверх или на одну клетку вправо. Прямая линия, которую пытается аппроксимировать моллюск, может быть задана следующим параметрическим уравнением:

x = - + Vx ■ t 2

где г возрастает с удалением моллюска от начальной точки. Таким образом, для принятия решения о том, в какую клетку перемещаться, необходимо лишь выяснить, какое условие наступит «раньше» (то есть при меньшем значении г): х = D + 1 или у = D + 1. Выписав соот-

х ■'у

ветствующие уравнения для переменной найдем, что моллюск перемещается вправо, если:

О +1 о„ +1

х 2 £ у 2

Ух

V

Здесь стоит знак «меньше или равно», так как, в соответствии с условием задачи, при прочих равных условиях, моллюск перемещается по горизонтали, то есть по оси X. Обратите внимание, что после приведения к общему знаменателю вышеприведенное условие может быть проверено в целых числах, без привлечения вещественной арифметики.

Используя эти рассуждения, несложно написать процедуру, которая моделирует перемещения двух моллюсков до их останова или до закраски определенного числа клеток. Моделирование перемещения всех пар моллюсков до их останова позволит вычислить максимально возможное число закрашенных клеток. Повторное моделирование перемещений всех пар моллюсков, вплоть до закраски этого числа клеток, позволит вычислить минимально необходимое время. После чего можно вывести ответ, например, снова промоделировав перемещение всех пар моллюсков и выводя номера тех из них, которые достигают найденных параметров.

Каждое моделирование перемещения пары моллюсков занимает время порядка О(тп). А весь алгоритм решения задачи (выполняющий моделирование перемещения для всех пар моллюсков) будет работать время порядка О(к2шп).

Задача О. Распределение памяти.

В ранних многозадачных системах оперативная память делилась на несколько областей фиксированного, но, возможно, различного размера. Сумма размеров всех областей равнялась размеру всей оперативной памяти. Получив набор программ, операционная система должна была так распределить их по областям памяти, чтобы они могли выполняться одновременно. Это не просто, так как время, кото-

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

В данной задаче вы должны определить оптимальное распределение задач по областям памяти. Вашей программе даны размеры всех областей памяти и для каждой программы описание того, как ее время выполнения зависит от количества доступной ей памяти. Вы должны найти план выполнения программ, который минимизирует среднее время цикла обработки программы. План выполнения - это назначение каждой программе области памяти и времени таким образом, чтобы две программы не использовали одну и ту же область памяти в одно и то же время и чтобы ни одной программе не была назначена область памяти меньшего размера, чем минимально ей необходимая. Цикл обработки программы - это время, прошедшее с момента подачи заявки на ее запуск (оно равняется нулю для всех программ в этой задаче) до того момента, когда программа закончит свое выполнение.

Входные данные (файл тетогу.ш).

Входной файл состоит из нескольких наборов тестовых данных. Каждый набор тестовых данных начинается со строки с двумя целыми числами т и п. Число т задает количество областей, на которые поделена память (1 < т < 10), а п - количество программ (1 < п < 50). Следующая строка содержит т положительных целых чисел, задающих размер т

областей памяти. Далее следуют п строк, задающих соответствие между количеством памяти и временем выполнения для каждой из п программ. Каждая строка начинается с положительного целого к (к < 10), за которым следует к пар положительных целых чисел s2, г2, ..., 5к, гк, удовлетворяющих условию si < для 1 < г < к. Минимальное количество памяти, которое необходимо программе, 5Г Если программа работает в области памяти 5, где < 5 < ^ для некоторого г, то ее время выполнения будет гг. Если программа работает в области памяти размера 5к или больше, то ее время выполнения будет гк.

После последнего набора тестовых данных идет пара нулей.

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

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

Для каждого набора тестовых данных сначала выведите его номер (начинайте с 1 и последовательно его увеличивайте). Затем выведите минимальное среднее время цикла обработки программы с двумя знаками после запятой. Далее выведите план выполнения, на котором достигается этот минимум. Выведите по одной строке на каждую программу в том порядке, в котором они даны во входном файле, что определит номер программы, область, в которой программа выполняется (нумерация в порядке входного файла), время начала выполнения программы и время, когда программа заканчивает свое выполнение. Придерживайтесь формата вывода, указанного в примере, и выводите пустую строку после каждого набора тестовых данных.

Если существует несколько планов выполнения, на которых достигается минимальное среднее время цикла обработки программы, то выведите любой из них.

Пример. Входной файл.

2 4 40 60 1 35 4 1 20 3 1 40 10

1 60 7

3 5

10 20 30

2 10 50 12 30 2 10 100 20 25 1 25 19

1 19 41

2 10 18 30 42 0 0

Вывод. Case 1

Average turnaround time = 7.75 Program 1 runs in region 1 from 0 to 4 Program 2 runs in region 2 from 0 to 3 Program 3 runs in region 1 from 4 to 14 Program 4 runs in region 2 from 3 to 10

Case 2

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Average turnaround time = 35.40 Program 1 runs in region 2 from 25 to 55 Program 2 runs in region 2 from 0 to 25 Program 3 runs in region 3 from 0 to 19 Program 4 runs in region 3 from 19 to 60 Program 5 runs in region 1 from 0 to 18

Решение.

Заметим, что среднее время цикла обработки - это сумма времени обработки по всем программам, поделенное на количество программ n, которое постоянно. Таким образом, нахождение минимального среднего времени цикла обработки программы эквивалентно нахождению минимального суммарного времени цикла обработки программы.

Проанализировав соответствие между количеством памяти и временем выполнения для каждой из n программ, составим таблицу (а .) для (1 < i < n,

1 < J < m), где а■■ - это время, за которое

ij

будет выполняться программа i, если ее запустить в регионе памяти j. Положим

а.. = ¥, если программа i не может выпол-

ij

няться в области памяти J. Например, вто-

рому тестовому набору из примера будет соответствовать таблица 1 (строки - программы, столбцы - области памяти).

Представим план выполнения в виде соответствия каждой программы некоторому положению в плане. Будем говорить, что программа г выполняется в положении (1 < у < т, 1 < к < п), если она выполняется к-ой с конца в у-ой области памяти. Например, программа в положении р21 выполняется последней во втором регионе памяти, а программа в положении р52 выполняется предпоследней в пятом регионе памяти. Вклад в суммарное время цикла обработки программы, вносимый программой г, выполняемой в положении рук, равен к • что учитывает собственно время выполнения программы и то, что ее выполнение увеличит время окончания к-1 программ, которые будут выполняться в этой области памяти после нее. Суммарное время цикла обработки программы будет суммой этих вкладов для каждой программы. Таким образом, задача сводится к известной задаче «о распределении» - нахождению паро-сочетания с оптимальным (в данном случае минимальным) весом во взвешенном двудольном графе. Например, для второго тестового набора из примера необходимо решить задачу распределения для матрицы, представленной в таблице 2 (строки - программы, столбцы - положения).

Выделенные ячейки таблицы соответствуют оптимальному распределению программ по положениям. Среднее время цикла обработки в этом случае равно (30+50+38+41+18)/5 = 35.4.

Нахождение оптимального распределения программ по положениям удобно производить за п шагов, на г-ом шаге (1 < г < п) добавляя новую программу и находя чередующуюся цепь с наименьшим весом, начинающуюся во вновь добавленной программе. Нахождение чередующейся цепи удобно производить с помощью алгоритма Форда-Беллмана, которому для этого потребуется О(г) итераций нахождения. При этом полезно заметить, что в наилучшей чередующейся цепи могут быть задействованы не более т+г-1 положений (г-1 уже занятых и т свободных), что позволяет построить алгоритм, время выполнения которого порядка О(п2(т+п)2).

Более подробно о графах и алгоритмах на них смотри, например, Кормен, Лейзерсон, Ривест «Алгоритмы: построение и анализ», МЦНМО, Москва, 2000.

регион программа 1 2 3

1 50 30 30

2 100 25 25

3 ¥ ¥ 19

4 ¥ 41 41

5 18 18 42

Таблица 1

положение 1,1 1,2 1,3 1,4 1,5 2,1 2,2 2,3 2,4 2,5 3,1 3,2 3,3 3,4 3,5

программа

1 50 100 150 200 250 30 60 90 120 150 30 60 90 120 150

2 100 200 300 400 500 25 50 75 100 125 25 50 75 100 125

3 8 8 8 8 8 8 8 8 8 8 19 38 57 76 95

4 8 8 8 8 8 41 82 123 164 205 41 82 123 164 205

5 18 36 54 72 90 18 36 54 72 90 42 84 126 168 210

Таблица 2

1 program AIRPORT;

2 const

3 MAX_N = 24; { Макс, число городов }

4 MAX_C = 20; { MaKC. число конфигураций }

5

6 type

7 TOutputLine = record { Строка выходной таблицы }

8 c: integer; { Идент. конфигурации }

9 t: longint; { Общая нагрузка }

10 end;

11

12 var

13 n: integer; { количество городов }

14 load: array[1..MAX_N, 1..MAX_N] of integer;

15 cnt: integer; { количество конфигураций }

16 totals: array[1..MAX_C] of TOutputLine;

17 sw: TOutputLine;

18 arrival: array[1..MAX_N] of integer;

19 departure: array[1..MAX_N] of integer;

20 k, a, b, c, i, j: integer;

21 t: longint;

22

23 begin

24 assign(input, "airport.in");

25 reset(input);

26 while true do begin { Цикл по всем наборам данных }

27 { Читаем транспортную нагрузку }

28 fillchar(load, sizeof(load), 0); { Очистка массива

29 read(n);

30 if n = 0 then

31 break;

32 for i := 1 to n do begin

33 read(a, k);

34 for j := 1 to k do begin

35 read(b);

36 read(load[a, b]);

37 end;

38 end;

39 { Читаем и обсчитываем каждую конфигурацию }

40 cnt := 0; { Будем считать количество кофигураций }

41 while true do begin { Цикл по конфигурациям }

42 { Читаем конфигурацию }

43 read(c);

44 if c = 0 then

45 break;

46 for i := 1 to n do

47 read(arrival[i]);

48 for i := 1 to n do

49 read(departure[i]);

50 { Обсчитываем конфигурацию }

51 t := 0; { Будем считам общую нагрузку }

52 for i := 1 to n do { Номера приб. входов }

53 for j := 1 to n do { Номера отб. входов }

54 inc(t, (abs(i - j) + 1) * load[arrival[i], departure[j]]);

55 { Запоминаем результаты в массиве totals }

56 inc(cnt);

57 totals[cnt].c := c;

58 totals[cnt].t := t;

59 end;

60 { Сортируем результаты }

61 for i := 1 to cnt - 1 do

62 for j := i + 1 to cnt do

63 if (totals[i].t > totals[j].t) or

64 ((totals[i].t = totals[j].t) and (totals[i].c > totals[j].c))

65 then begin

66 { Поменяем местами totals[i] и totals[j] }

67 sw := totals[i];

68 totals[i] := totals[j];

69 totals[j] := sw;

70 end;

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

71 { Выводим результаты }

72 writeln("Configuration Load");

73 for i := 1 to cnt do

74 writeln(totals[i].c:5, " ":10, totals[i].t);

75 end;

76 end.

© Наши авторы, 2001. Our authors, 2001.

Елизаров Роман Анатольевич, председатель жюри Северо-Восточного Европейского региона Всемирных студенческих соревнований по программированию (АСМ).

i Надоели баннеры? Вы всегда можете отключить рекламу.