Задача взята с сайта e-olymp.com.
Условие задачи
В таблице из [latex]n[/latex] строк и [latex]n[/latex] столбцов некоторые клетки заняты шариками, другие свободны. Выбран шарик, который нужно переместить, и место, куда его переместить. Выбранный шарик за один шаг перемещается в соседнюю по горизонтали или вертикали свободную клетку. Требуется выяснить, возможно ли переместить шарик из начальной клетки в заданную, и если возможно, то найти путь из наименьшего количества шагов.
Входные данные
В первой строке находится число [latex]n \left (2\leq n\leq 40 \right )[/latex], в каждой из следующих [latex]n[/latex] строк — по [latex]n[/latex] символов. Символом точки обозначена свободная клетка, латинской заглавной [latex]O[/latex] — шарик, [latex]@[/latex] — исходное положение шарика, который должен двигаться, латинской заглавной [latex]X[/latex] — конечное положение шарика.
Выходные данные
В первой строке выводится [latex]Y[/latex], если движение возможно, или [latex]N[/latex], если нет. Если движение возможно далее следует [latex]n[/latex] строк по [latex]n[/latex] символов — как и на вводе, но [latex]X[/latex], а также все точки на пути заменяются плюсами.
Тесты
Входные данные | Выходные данные | ||||
|
|
||||
|
|
||||
|
|
Код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#include <iostream> #include <queue> using namespace std; /* нахождение пути*/ void find_path(int n, int row, int col, char** lab, int** visited, int** path, queue<int>& plan){ if(!visited[row][col]){ /* проверяем не вышли ли мы за границы лабиринта, есть ли клетка в массиве посещенных и можно ли через нее пройти*/ if ((row+1) < n && (row+1) >= 0 && !visited[row+1][col] && (lab[row+1][col] == '.' || lab[row+1][col] == 'X')) { path[row+1][col] = path[row][col] + 1; plan.push(row+1); plan.push(col); } if((row-1) < n && (row-1) >= 0 && !visited[row-1][col] && (lab[row-1][col] == '.' || lab[row-1][col] == 'X')) { path[row-1][col] = path[row][col] + 1; plan.push(row-1); plan.push(col); } if((col + 1) < n && (col + 1) >= 0 && !visited[row][col+1] && (lab[row][col+1] == '.' || lab[row][col+1] == 'X')) { path[row][col+1] = path[row][col] + 1; plan.push(row); plan.push(col+1); } if((col - 1) < n && (col - 1) >= 0 && !visited[row][col-1] && (lab[row][col-1] == '.' || lab[row][col-1] == 'X')) { path[row][col-1] = path[row][col] + 1; plan.push(row); plan.push(col-1); } visited[row][col] = 1; /* отмечаем клетку в которой побывали */ } } int main() { int n, x_start, y_start, x_end, y_end, x, y; queue <int> plan; cin >> n; char** lab = new char* [n]; int** visited = new int * [n]; int** path = new int * [n]; for(int i=0; i<n; i++){ lab[i] = new char [n]; /* массив для хранения лабиринта */ visited[i] = new int [n]; /* массив для хранения информации о посещении клеток*/ path[i] = new int [n]; /* массив для хранения найденных путей */ for(int j=0; j<n; j++){ visited[i][j] = 0; path[i][j] = -1; cin >> lab[i][j]; if (lab[i][j] == '@') { /* находим начало пути*/ x_start = i; y_start = j; plan.push(i); /* заносим начальную клетку */ plan.push(j); /* в план посещения */ path[i][j] = 1; } else if (lab[i][j] == 'X') { /* находим конечную точку */ x_end = i; y_end = j; } } } while(!plan.empty()){ /* пока очередь посещения клеток непустая*/ x=plan.front(); plan.pop(); y=plan.front(); plan.pop(); find_path(n, x, y, lab, visited, path, plan); /* продолжаем поиск пути*/ } if(!visited[x_end][y_end]){ cout << "N" << endl; } else { cout << "Y" << endl; x = x_end; y = y_end; lab[x][y] = '+'; while (path[x][y] != 2) { /* восстановление пути*/ if ((x-1) >= 0 && (x-1) < n && (path[x-1][y] == path[x][y] - 1)) { x = x-1; lab[x][y] = '+'; } else if ((x+1) >= 0 && (x+1) < n && (path[x+1][y] == path[x][y] - 1)) { x = x+1; lab[x][y] = '+'; } else if ((y-1) >= 0 && (y-1) < n && (path[x][y-1] == path[x][y] - 1)) { y = y-1; lab[x][y] = '+'; } else if ((y+1) >= 0 && (y+1) < n && (path[x][y+1] == path[x][y] - 1)) { y = y+1; lab[x][y] = '+'; } } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cout << lab[i][j]; } cout << endl; } } return 0; } |
Засчитанное решение на e-olymp.com.
Решение
Для решения данной задачи можно использовать волновой алгоритм. Считывая исходный массив с лабиринтом находим индексы начального и конечного положения шарика. Затем, начиная с начальной позиции проверяем проходимы ли соседние с ней клетки . Если клетка проходима и не была посещена ранее, помещаем ее в очередь и присваиваем соответствующей клетке массива, в котором хранится путь, значение на единицу большее, чем в начальной клетке. Так каждая помеченная клетка становится начальной, порождая шаги в соседние клетки, пока очередь не опустеет.
Затем, если клетка с конечным положением шарика достижима, необходимо восстановить кратчайший путь. Двигаясь от конечной позиции в начальную, на каждом шаге выбираем клетку значение которой на единицу меньше текущего положения, при этом символы в соответствующих клетках исходного лабиринта заменяем на символ [latex]+.[/latex]
Для отправки комментария необходимо войти на сайт.