我正在尝试使用广度优先搜索制作迷宫求解器,并使用字符'*'标记最短路径
迷宫实际上只是一堆文字。迷宫由一个n x n网格组成,由作为墙的“#”符号和句点“。”组成。代表可步行区域/路径。 'S'表示开始,'F'表示结束。现在,这个功能似乎没有找到解决方案(它认为即使有一个是不可能的,它也有解决方案)。我正在检查这四个邻居,如果它们“未发现”(-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;
}
答案 0 :(得分:0)
一些评论:
int delta[] = {-1, cols, 1 -cols};
然后你可以简单地遍历所有四个方面,你不应该复制粘贴相同的代码。
while (finish != start) { maze[finish] = '*'; finish = prd[finish]; } maze[start] = '*';
当然,这个循环应该在最后一次,因为你不知道那个时刻你是否已经达到目的
PS最好清除你在功能中分配的内存
答案 1 :(得分:0)
通过邻居迭代可以大大简化(我知道这有点类似于kobra建议但可以进一步改进)。我使用一个移动数组来定义给定移动的x和y delta,如下所示:
int moves[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
请注意,不仅tis列出了来自给定单元格的所有可能移动,但它也以顺时针方向列出它们,这对某些问题很有用。
现在遍历数组我使用std::queue<pair<int,int> >
这样,当前位置由与其对应的坐标对定义。这是我如何循环通过gien单元格的邻居c:
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.
}
我知道这段代码与你的代码并没有多大关系,但是当我教这个问题时,相信我很多学生在向他们展示这种方法时真的很感激。
现在回到你的问题 - 你需要从结束位置开始并使用prd数组找到它的父级,然后找到它的父级的父级,依此类推,直到你到达具有否定父级的单元格。您所做的是考虑所有访问过的单元格,其中一些单元格不在从S
到F
的最短路径上。
设置solved = true
后,您可以中断,这会稍微优化算法。
我个人认为你总能找到一个解决方案,因为你没有检查掉落的情况。 (我的代码中的if (ti < 0 || ti >= n || tj < 0 || tj >= m)
位。)
希望这会对您有所帮助,并为您提供一些如何改进编码的提示。