При закрытии подписчики были переданы в рассылку "Обзор инструментов SEO-оптимизатора и методов продвижения" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Информационный Канал Subscribe.Ru |
Олимпиадные задачи и алгоритмы на C++Здравствуйте, уважаемые подписчики.
Поиск в ширину на примере задачи о лабиринте.Постановка задачи. Лабиринт задан таблицей n*m из символов. Символ '#' - означает стену, '.' - пустое пространство, 's' - начальную позицию, 'f' - конечную позицию. Игрок может находиться только в пустых клетках. Из клетки он может перемещаться в соседнюю по горизонтали или по вертикали, но не по диагонали. Требуется найти кратчайший путь из начальной клетки в конечную. Пример лабиринта и кратчайшего пути в нем (n=4, m=6): ...... 23456. s#.#.. 1#.#7. .#.#.. .#.#8. ...#f. ...#9. Решение. Для решения используется алгоритм поиска в ширину. Собственно, поиском в ширину его обычно называют, когда говорят про графовые алгоритмы. В задачах о лабиринтах его чаще называют волновым алгоритмом, или просто волной. // ------------------------------------------------------------------------- // lab - двухмерный массив, в котором хранится лабиринт // n,m - количество строк и столбцов в массиве lab // si,sj - начальная позиция // fi,fj - конечная позиция typedef struct point {int i, j;} point; int di[4] = { -1, 0, 1, 0}; int dj[4] = { 0, 1, 0, -1}; int i,j; int d[n][m]; // массив расстояний int head,tail; // указатели очереди point queue[n*m]; // очередь // обнуляем массив расстояний for (i = 0; i < n; i++) for (j = 0; j < m; j++) d[i][j] = 0; d[si][sj] = 1; // расстояние до начальной клетки равно 1 // инициализируем очередь head = tail = 0; queue[tail].i = si; queue[tail++].j = sj; // заносим в очередь начальную клетку while (head < tail) // цикл пока очередь не пуста { point p = queue[head++]; // берем следующую позицию из очереди for (int k = 0; k < 4; k++) // цикл по соседним клеткам { point newp; newp.i = p.i + di[k]; newp.j = p.j + dj[k]; // проверяем, что такая клетка есть if (0 <= newp.i && newp.i < n && 0 <= newp.j && newp.j < m) // проверяем, что она свободна и ранее ее не посещали if (lab[newp.i][newp.j] != '#' && d[newp.i][newp.j] == 0) { d[newp.i][newp.j] = d[p.i][p.j] + 1; // находим расстояние queue[tail++] = newp; // заносим позицию в очередь } } } if (d[fi][fj]) printf("расстояние = %d\n", d[fi][fj]); else printf("нет ни одного пути"); // ------------------------------------------------------------------------- Массив d используется для хранения расстояний от начальной клетки до каждой из остальных. Если d[i][j] = 0, то расстояние до клетки (i,j) еще неизвестно. Клетки обрабатываются в порядке увеличения расстояния. Для этого используется очередь. При обработке клетки в очередь заносятся все соседние с ней, расстояние до которых еще не известно. Причем расстояние до них устанавливается равным расстоянию до текущей клетки плюс один. Рассмотрим работу алгоритма на приведенном выше примере. Порядок занесения клеток в очередь будет следующий: (1,0), (0,0), (2,0), (0,1), (3,0), (0,2), (3,1), (0,3), (1,2), (3,2), (0,4), (2,2), (0,5), (1,4), (1,5), (2,4), (2,5), (3,4), (3,5). Значения элементов массива d: ...... 2 3 4 5 6 7 s#.#.. 1 0 5 0 7 8 .#.#.. 2 0 6 0 8 9 ...#f. 3 4 5 0 9 10 Приведенный выше алгоритм находит только длину кратчайшего пути. Сам путь можно восстановить с конца с помощью массива d. Последней клеткой в пути будет (fi,fj). Предпоследняя клетка (i,j) - это одна из соседних с (fi,fj) клеток, для которой d[i][j] = d[fi][fj] - 1. Затем выбираем клетку, соседнюю с предпоследней, расстояние до которой равно d[fi][fj] - 2, и так далее, пока не дойдем до (si,sj).
Входной файл: input.txt |
Секунда | Преобразование | Колонии | |||||||
---|---|---|---|---|---|---|---|---|---|
0-я | 1-я | 2-я | 3-я | 4-я | 5-я | 6-я | 7-я | ||
начало | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | |
1-я | reproduce 2 5 | 1 | 1 | 5 | 1 | 1 | 1 | 1 | 1 |
2-я | copy 4 2 | 1 | 1 | 5 | 1 | 6 | 1 | 1 | 1 |
3-я | die 1 0 | 1 | 0 | 5 | 1 | 6 | 1 | 1 | 1 |
4-я | merry-go-round 0 0 | 1 | 1 | 0 | 5 | 1 | 6 | 1 | 1 |
5-я | teleport 5 3 | 1 | 1 | 0 | 0 | 1 | 4 | 1 | 1 |
6-я | swap 0 2 | 0 | 1 | 1 | 0 | 1 | 4 | 1 | 1 |
7-я | reproduce 2 5 | 0 | 1 | 5 | 0 | 1 | 4 | 1 | 1 |
8-я | copy 4 2 | 0 | 1 | 5 | 0 | 6 | 4 | 1 | 1 |
9-я | die 1 0 | 0 | 0 | 5 | 0 | 6 | 4 | 1 | 1 |
10-я | merry-go-round 0 0 | 1 | 0 | 0 | 5 | 0 | 6 | 4 | 1 |
11-я | teleport 5 3 | 1 | 0 | 0 | 0 | 0 | 4 | 4 | 1 |
На проверку принимаются решения, написанные на языке C++. Отправляйте свои письма по адресу accepted@narod.ru. Решение должно содержаться в одном файле, вложенном в ваше письмо. Для компиляции, по вашему выбору, будет использоваться программа bcc.exe (Borland C++ 3.1) или cl.exe (Microsoft Visual C++ 6.0). Размер исходного кода не должен превышать 40 Kb. Для каждой задачи отправляйте отдельное письмо. В теле письма укажите следующие данные (пример):
ник (*): vasya пароль (*): a193z458w2 фамилия: Иванов имя: Василий e-mail: vasya@hotmail.com номер задачи (*): 1 компилятор (*): cl
(*) обозначены обязательные для заполнения поля. Ник и пароль вы сами придумаете при отправке своего первого письма. В последующих письмах указывайте те же самые ник и пароль. Я пока не придумал, что делать, если два человека используют один и тот же ник. Так что, старайтесь придумать его так, чтобы никто до вас его еще не придумал :-) Если вы укажите свой e-mail, то с этой проблемой будет легче разобраться. В качестве компилятора укажите bcc или cl. И, главное, не забудьте указать номер задачи!
При проверке решений, используются стандартные правила acm. Их можно найти, например, на сайте http://acm.baylor.edu. Проверка решений осуществляется на наборе тестов, недоступных участникам. Решение считается принятым, если выдало верный ответ на каждом из тестов. Программа должна считывать данные из указанного в условии входного файла и выдавать результат в указанный в условии выходной файл. Она не должна работать с другими файлами или каталогами. Входной файл нельзя открывать для записи. При доступе к входному и выходному файлу вы должны предполагать, что они находятся в текущей директории. Не используйте консольный ввод или вывод.
Решения принимаются до субботы следующей недели (8 мая 2004) включительно. В воскресенье (9 мая 2004) вечером будут высланы результаты тестирования и авторские решения.
Ведущий рассылкой: Виктор Журавлев
Вопросы, пожелания, предложения пишите на мой
e-mail.
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||