БФС Maze помогите с++
Я пытаюсь сделать лабиринт-решатель, используя поиск по ширине, и отметить кратчайший путь с помощью символа ' * '
На самом деле лабиринт-это просто куча текста. Лабиринт состоит из n x n сетки, состоящей из символов"#", которые являются стенами и периодами."представляя проходимую область / пути. "S" означает начало, " F " - конец. Прямо сейчас эта функция, похоже, не находит решения (она думает, что у нее есть решение, даже когда оно невозможно). Я проверяю ... четыре соседа, и если они 'unfound' (-1), они добавляются в очередь для обработки.Лабиринт работает на нескольких лабиринтах, но не на этом:
...###.#....
##.#...####.
...#.#.#....
#.####.####.
#F..#..#.##.
###.#....#S.
#.#.####.##.
....#.#...#.
.####.#.#.#.
........#...
Чего не хватает в моей логике?
int mazeSolver(char *maze, int rows, int cols)
{
int start = 0;
int finish = 0;
for (int i=0;i<rows*cols;i++) {
if (maze[i] == 'S') { start=i; }
if (maze[i] == 'F') { finish=i; }
}
if (finish==0 || start==0) { return -1; }
char* bfsq;
bfsq = new char[rows*cols]; //initialize queue array
int head = 0;
int tail = 0;
bool solved = false;
char* prd;
prd = new char[rows*cols]; //initialize predecessor array
for (int i=0;i<rows*cols;i++) {
prd[i] = -1;
}
prd[start] = -2; //set the start location
bfsq[tail] = start;
tail++;
int delta[] = {-cols,-1,cols,+1}; // North, West, South, East neighbors
while(tail>head) {
int front = bfsq[head];
head++;
for (int i=0; i<4; i++) {
int neighbor = front+delta[i];
if (neighbor/cols < 0 || neighbor/cols >= rows || neighbor%cols < 0 || neighbor%cols >= cols) {
continue;
}
if (prd[neighbor] == -1 && maze[neighbor]!='#') {
prd[neighbor] = front;
bfsq[tail] = neighbor;
tail++;
if (maze[neighbor] == 'F') { solved = true; }
}
}
}
if (solved == true) {
int previous = finish;
while (previous != start) {
maze[previous] = '*';
previous = prd[previous];
}
maze[finish] = 'F';
return 1;
}
else { return 0; }
delete [] prd;
delete [] bfsq;
}
2 ответа:
Перебор соседей может быть значительно упрощен(я знаю, что это несколько похоже на то, что предлагает кобра, но это может быть улучшено дальше). Я использую массив ходов, определяющий дельту x и y данного хода следующим образом:
Обратите внимание, что tis не только перечисляет все возможные ходы из данной ячейки, но и перечисляет их по часовой стрелке, что полезно для некоторых задач. Теперь для обхода массива я используюint moves[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
std::queue<pair<int,int> >
Таким образом, текущая позиция определяется парой соответствующих ему координат. Вот как я циклически перебираю соседей клетки gien c:Я знаю, что этот код на самом деле не связан с вашим кодом, но поскольку я преподаю такого рода проблемы, поверьте мне, многие студенты были очень благодарны, когда я показал им этот подход. Теперь вернемся к вашему вопросу - вам нужно начать с конечной позиции и использовать массив prd, чтобы найти его родителя, затем найти родителя его родителя и так далее, пока вы не достигнете ячейки с отрицательным родителем. То, что вы делаете вместо этого, учитывает все посещенные ячейки, и некоторые из них не находятся на кратчайшем пути отpair<int,int> c; for (int l = 0;l < 4/*size of moves*/;++l){ int ti = c.first + moves[l][0]; int tj = c.second + moves[l][1]; if (ti < 0 || ti >= n || tj < 0 || tj >= m) { // This move goes out of the field continue; } // Do something. }
S
доF
.Вы можете сломать, как только вы установите
Я лично думаю, что вы всегда находите решение, потому что у вас нет чека на падение с поля. (битsolved = true
это немного оптимизирует алгоритм.if (ti < 0 || ti >= n || tj < 0 || tj >= m)
в моем коде).Надеюсь, это поможет вам и даст несколько советов, как улучшить ваше кодирование.
Несколько комментариев:
- Вы можете использовать контейнер очереди в c++, его гораздо проще в использовании
- в этой задаче вы можете написать что-то вроде:
int delta[] = {-1, cols, 1 -cols};
И тогда вы просто можете перебирать все четыре стороны, вы не должны копировать-вставлять один и тот же код.
- у вас будут проблемы с границами вашего массива. Потому что вы его не проверяете.
- Когда вы основали finish, вы должны прервать цикл
- и в последнем цикле вы есть ошибка. Он напечатает * во всех ячейках, в которых вы были (не только оптимальным способом). Он должен выглядеть:
while (finish != start) { maze[finish] = '*'; finish = prd[finish]; } maze[start] = '*';
И конечно же этот цикл должен быть в последнем случае, потому что вы не знаете, достигнете ли вы в этот момент конца или нет
PS и его лучше очистить от памяти, которую вы выделили в функцию