迷宫遍历打印每条可能的路径 C++
Maze Traversal prints every possible path C++
这是我关于堆栈溢出的第一个问题,这是我的作业。我要做的就是找到从头到尾所有可能的路径。我正在做的是,如果找到 '-'
并且函数的参数是 '-'
所在的索引,我将调用该函数。当前参数被压入堆栈。在进一步解释之前,我想展示输出和迷宫。
迷宫
5 6
s - - - - -
- * * * * -
- * * * * -
- * * * * -
- - - - - e
开始的两个 int
是行和列。
输出
00,01,11,21,22,02,03,13,23,22,04,05,15,25,35,45,44,43,42,32,22
从栈中取出输出。
在某种程度上,输出是正确的,因为您可以看到该函数正在遍历每条路径。我无法做的是跟踪功能以及我为什么要这样做?因为我想从头开始打印所有路径(在本例中为 0、0)。当函数有两条路径要遍历时,如何跟踪函数以便我可以从起始索引打印它?
预期输出
00,01,11,21,22
00,01,02,03,13,23,22
00,01,02,03,04,05,15,25,35,45,44,43,42,32,22
如有必要,我也会提供代码。
我有编辑代码。我正在将索引 (1,0) 推入堆栈,例如先 0 然后 1,然后弹出两个以将其删除。
我理解为什么我的输出是这样的(如上所述),因为,以 (0,0) 处程序中的迷宫为例,它有向上或向下两个选项。它下降了,因为所有这些语句都是 if not if else 程序在函数执行后检查其他条件,所以它转到另一个正确的选项。好的,那么输出呢?所有索引都被压入堆栈,当找到 'e' 时,它会打印所有存储的索引,但不会删除它们。对于这个例子,我可以在打印后从堆栈中弹出所有内容,输出会很好(不重复)
再举个例子
例子
6 6
小号 1 1 1 1 1
0 0 1 0 0 1
0 0 1 0 0 1
0 0 1 0 0 1
0 0 1 0 0 1
0 0 1 1 1 e
在此示例中,您可以看到它在 (0,2) 处有两个选项,因此我无法在到达第一个路径末端后从此处弹出堆栈中的所有内容。因为它也会弹出 (0,0) 和 (0,1)。我想要的是只弹出到 (0,2)
这就是我想要做的。
#include<iostream>
#include<string.h>
#include<fstream>
using namespace std;
ofstream fout("Q1(output).txt");
ifstream fin("Q1.txt");
class stack
{
private:
int row,col;
int top;
string str;
int sourceA,sourceB,destinationA,destinationB;
char **store;//arr which has maze is passed into class . 'store' has maze.
public:
stack(int row,int col)//constructor , paramerters are rows and cols
{
this->row=row;
this->col=col;
top=-1;
sourceA=0;
sourceB=0;
}
void finish()
{
while(top!=-1)
{
top--;
}
}
void push(int dataA,int dataB )//push two indexes in str like (0,1) pushed as first 0 then 1
{
if(top==-1)
{
top++;
str[top]=dataA ;
top++;
str[top]=dataB ;
}
else
{
top++;
str[top]='1';
top++;
str[top]=dataA ;
top++;
str[top]=dataB ;
}
}
void pop(int varA ,int varB)//This function was made for other purpose but not used
{
for(int a=0;a<top+1;a++)
{
if(a==varA && a+1==varB )
{
top=a-2;
cout<<top;
}
}
cout<<endl;
}
int ret()
{
return top;
}
void empty()
{
if(top==-1)
cout<<"\nEmpty\n";
else
cout<<"\nNot Empty\n";
}
void get(char **arr)// saving arr(Maze) into store
{
char ch;
store=NULL;
store=new char*[row];
for(int a=0;a<row;a++)
{
store[a]=new char[col];
for(int b=0;b<col;b++)
{
store[a][b]=arr[a][b];
cout<<store[a][b];
if(arr[a][b]=='s')
{
sourceA=a;//saving the 's' index , my inititate starts from here .
sourceB=b;
}
else if(arr[a][b]=='e')
{
destinationA=a;//saving the 'e' index , used later.
destinationB=b;
}
}
cout<<endl;
}
}
int getA()
{
return sourceA;
}
int getB()
{
return sourceB;
}
int getAD()
{
return destinationA;
}
int getBD()
{
return destinationB;
}
int initiate(int a,int b)
{
int tempA,tempB;
push(a,b);
if(a>0 )
{
if(store[a-1][b]=='1'&&store[a-1][b]!='v')
{
store[a][b]='v';
initiate(a-1,b);
store[a][b]='1' ;
}
}
if(b>0 )
{
if(store[a][b-1]=='1'&&store[a][b-1]!='v')
{
store[a][b]='v';
initiate(a,b-1);
store[a][b]='1' ;
}
}
if(a!=row-1)
{
if(store[a+1][b]=='1'&&store[a+1][b]!='v')
{
store[a][b]='v';
initiate(a+1,b);
store[a][b]='1' ;
}
}
if(b!=col-1)
{
if(store[a][b+1]=='1'&&store[a][b+1]!='v')
{
store[a][b]='v';
initiate(a,b+1);
store[a][b]='1' ;
}
}
if(a+1==destinationA && b==destinationB ||a-1==destinationA && b==destinationB ||a==destinationA && b+1==destinationB ||a==destinationA && b-1==destinationB )
{
push(destinationA,destinationB);
cout<<"\nPath : \n";
print1();
}
pop();
}
void print1()
{
for(int a=0;a<top+1;a++)
{
if(str[a]!='1')
{
int ret=str[a];
cout<<ret;
fout<<ret;
}
else
{
cout<<endl;
fout<<endl;
}
}
fout.close();
}
int pop()
{
int ret=str[top];
top--;
int ret1=str[top];
top--;
}
void show()
{
cout<<endl<<endl;
for(int a=0;a<row;a++)
{
for(int b=0;b<col;b++)
{
cout<<store[a][b];
}
cout<<endl;
}
}
};
main()
{
char ch;
int row,col;
fin >> row;
fin >> col;
stack s(row,col);
char **arr=NULL;
arr=new char*[row];
for(int a=0;a<row;a++)
{
arr[a]=new char[col];
for(int b=0;b<col;b++)
{
fin>>ch;
arr[a][b]=ch;
}
}
fin.close();
s.get(arr);
s.initiate(s.getA(),s.getB());
s.show();
exit(1);
}
打印所有路径可以像您一样使用递归来完成,但是您需要跟踪您为达到目标所走的路径,并在每次到达目的地时打印它或保存它在一个容器中。我更喜欢后一种方法。该路径可以是堆栈或其他支持 push/pop 操作的结构。您在遍历中访问的每个节点都应添加到路径中,并在其所有邻居都已完全展开后弹出。
这是伪代码中的递归路径构建算法:
function DFS(row: int, col: int, maze: char[][], path: int[][], result: int[][][]) {
path.push([row, col])
if ([row, col] is the destination) {
result.add(path)
}
else {
for (direction in each_cardinal_direction) {
new_row = row + direction.row
new_col = col + direction.col
if (in_bounds(new_row) and in_bounds(new_col) and
maze[new_row][new_col] is unvisited) {
maze[row][col] = visited
DFS(new_row, new_col, maze, path, result)
maze[row][col] = unvisited
}
}
}
path.pop()
}
我不是很清楚你为什么同时使用显式和隐式状态;通常,当 运行 和 DFS 时,使用显式堆栈和 while
循环或使用递归并将所有状态存储为调用堆栈上的帧。考虑改进命名清晰度、设计和 spacing/indentation,以便您的逻辑更容易理解。
例如,str
是一个充当堆栈的数组,应该这样命名,而您的 stack
class 实际上根本不是堆栈,而是而是一个迷宫求解器。您的 pop
函数不准确,一次只能删除一个元素。
此外,由于您使用的是 C++ classes 和字符串,您也可以利用容器。
这是一个临时修改迷宫的递归示例,添加墙壁以标记访问过的节点以避免循环:
#include <iostream>
#include <vector>
void DFS(
int row, int col,
std::vector<std::vector<char>> &maze,
std::vector<std::pair<int, int>> &path,
std::vector<std::vector<std::pair<int, int>>> &result
) {
path.push_back(std::make_pair(row, col));
if (maze[row][col] == 'e') {
result.push_back(path);
}
else {
int dirs[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
for (auto d : dirs) {
int r = d[0] + row;
int c = d[1] + col;
if (r >= 0 && c >= 0 && r < maze.size() &&
c < maze[r].size() && maze[r][c] != '*') {
maze[row][col] = '*';
DFS(r, c, maze, path, result);
maze[row][col] = '-';
}
}
}
path.pop_back();
}
std::vector<std::vector<std::pair<int, int>>>
getPaths(std::vector<std::vector<char>> maze) {
std::vector<std::vector<std::pair<int, int>>> result;
std::vector<std::pair<int, int>> path;
int row = -1;
int col = -1;
for (int i = 0; i < maze.size() && row == -1; i++) {
for (int j = 0; j < maze[i].size() && col == -1; j++) {
if (maze[i][j] == 's') {
row = i;
col = j;
}
}
}
DFS(row, col, maze, path, result);
return result;
}
int main() {
std::string raw = "s-----\n*-*-*-\n*-e-*-\n**-**-\n**----";
std::vector<std::vector<char>> maze;
std::vector<char> row;
for (int i = 0; i < raw.size(); i++) {
if (raw[i] == '\n') {
maze.push_back(row);
row.clear();
}
else {
row.push_back(raw[i]);
}
}
maze.push_back(row);
for (auto &path : getPaths(maze)) {
std::cout << std::endl << '[';
for (auto &cell : path) {
std::cout << '(' << cell.first <<
"," << cell.second << ')';
}
std::cout << ']' << std::endl;
}
}
输出:
[(0,0)(0,1)(0,2)(0,3)(0,4)(0,5)(1,5)(2,5)(3,5)(4,5)(4,4)(4,3)(4,2)(3,2)(2,2)]
[(0,0)(0,1)(0,2)(0,3)(1,3)(2,3)(2,2)]
[(0,0)(0,1)(1,1)(2,1)(2,2)]
这是我关于堆栈溢出的第一个问题,这是我的作业。我要做的就是找到从头到尾所有可能的路径。我正在做的是,如果找到 '-'
并且函数的参数是 '-'
所在的索引,我将调用该函数。当前参数被压入堆栈。在进一步解释之前,我想展示输出和迷宫。
迷宫
5 6
s - - - - -
- * * * * -
- * * * * -
- * * * * -
- - - - - e
开始的两个 int
是行和列。
输出
00,01,11,21,22,02,03,13,23,22,04,05,15,25,35,45,44,43,42,32,22
从栈中取出输出。
在某种程度上,输出是正确的,因为您可以看到该函数正在遍历每条路径。我无法做的是跟踪功能以及我为什么要这样做?因为我想从头开始打印所有路径(在本例中为 0、0)。当函数有两条路径要遍历时,如何跟踪函数以便我可以从起始索引打印它?
预期输出
00,01,11,21,22
00,01,02,03,13,23,22
00,01,02,03,04,05,15,25,35,45,44,43,42,32,22
如有必要,我也会提供代码。 我有编辑代码。我正在将索引 (1,0) 推入堆栈,例如先 0 然后 1,然后弹出两个以将其删除。 我理解为什么我的输出是这样的(如上所述),因为,以 (0,0) 处程序中的迷宫为例,它有向上或向下两个选项。它下降了,因为所有这些语句都是 if not if else 程序在函数执行后检查其他条件,所以它转到另一个正确的选项。好的,那么输出呢?所有索引都被压入堆栈,当找到 'e' 时,它会打印所有存储的索引,但不会删除它们。对于这个例子,我可以在打印后从堆栈中弹出所有内容,输出会很好(不重复) 再举个例子
例子
6 6 小号 1 1 1 1 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 1 1 e
在此示例中,您可以看到它在 (0,2) 处有两个选项,因此我无法在到达第一个路径末端后从此处弹出堆栈中的所有内容。因为它也会弹出 (0,0) 和 (0,1)。我想要的是只弹出到 (0,2)
这就是我想要做的。
#include<iostream>
#include<string.h>
#include<fstream>
using namespace std;
ofstream fout("Q1(output).txt");
ifstream fin("Q1.txt");
class stack
{
private:
int row,col;
int top;
string str;
int sourceA,sourceB,destinationA,destinationB;
char **store;//arr which has maze is passed into class . 'store' has maze.
public:
stack(int row,int col)//constructor , paramerters are rows and cols
{
this->row=row;
this->col=col;
top=-1;
sourceA=0;
sourceB=0;
}
void finish()
{
while(top!=-1)
{
top--;
}
}
void push(int dataA,int dataB )//push two indexes in str like (0,1) pushed as first 0 then 1
{
if(top==-1)
{
top++;
str[top]=dataA ;
top++;
str[top]=dataB ;
}
else
{
top++;
str[top]='1';
top++;
str[top]=dataA ;
top++;
str[top]=dataB ;
}
}
void pop(int varA ,int varB)//This function was made for other purpose but not used
{
for(int a=0;a<top+1;a++)
{
if(a==varA && a+1==varB )
{
top=a-2;
cout<<top;
}
}
cout<<endl;
}
int ret()
{
return top;
}
void empty()
{
if(top==-1)
cout<<"\nEmpty\n";
else
cout<<"\nNot Empty\n";
}
void get(char **arr)// saving arr(Maze) into store
{
char ch;
store=NULL;
store=new char*[row];
for(int a=0;a<row;a++)
{
store[a]=new char[col];
for(int b=0;b<col;b++)
{
store[a][b]=arr[a][b];
cout<<store[a][b];
if(arr[a][b]=='s')
{
sourceA=a;//saving the 's' index , my inititate starts from here .
sourceB=b;
}
else if(arr[a][b]=='e')
{
destinationA=a;//saving the 'e' index , used later.
destinationB=b;
}
}
cout<<endl;
}
}
int getA()
{
return sourceA;
}
int getB()
{
return sourceB;
}
int getAD()
{
return destinationA;
}
int getBD()
{
return destinationB;
}
int initiate(int a,int b)
{
int tempA,tempB;
push(a,b);
if(a>0 )
{
if(store[a-1][b]=='1'&&store[a-1][b]!='v')
{
store[a][b]='v';
initiate(a-1,b);
store[a][b]='1' ;
}
}
if(b>0 )
{
if(store[a][b-1]=='1'&&store[a][b-1]!='v')
{
store[a][b]='v';
initiate(a,b-1);
store[a][b]='1' ;
}
}
if(a!=row-1)
{
if(store[a+1][b]=='1'&&store[a+1][b]!='v')
{
store[a][b]='v';
initiate(a+1,b);
store[a][b]='1' ;
}
}
if(b!=col-1)
{
if(store[a][b+1]=='1'&&store[a][b+1]!='v')
{
store[a][b]='v';
initiate(a,b+1);
store[a][b]='1' ;
}
}
if(a+1==destinationA && b==destinationB ||a-1==destinationA && b==destinationB ||a==destinationA && b+1==destinationB ||a==destinationA && b-1==destinationB )
{
push(destinationA,destinationB);
cout<<"\nPath : \n";
print1();
}
pop();
}
void print1()
{
for(int a=0;a<top+1;a++)
{
if(str[a]!='1')
{
int ret=str[a];
cout<<ret;
fout<<ret;
}
else
{
cout<<endl;
fout<<endl;
}
}
fout.close();
}
int pop()
{
int ret=str[top];
top--;
int ret1=str[top];
top--;
}
void show()
{
cout<<endl<<endl;
for(int a=0;a<row;a++)
{
for(int b=0;b<col;b++)
{
cout<<store[a][b];
}
cout<<endl;
}
}
};
main()
{
char ch;
int row,col;
fin >> row;
fin >> col;
stack s(row,col);
char **arr=NULL;
arr=new char*[row];
for(int a=0;a<row;a++)
{
arr[a]=new char[col];
for(int b=0;b<col;b++)
{
fin>>ch;
arr[a][b]=ch;
}
}
fin.close();
s.get(arr);
s.initiate(s.getA(),s.getB());
s.show();
exit(1);
}
打印所有路径可以像您一样使用递归来完成,但是您需要跟踪您为达到目标所走的路径,并在每次到达目的地时打印它或保存它在一个容器中。我更喜欢后一种方法。该路径可以是堆栈或其他支持 push/pop 操作的结构。您在遍历中访问的每个节点都应添加到路径中,并在其所有邻居都已完全展开后弹出。
这是伪代码中的递归路径构建算法:
function DFS(row: int, col: int, maze: char[][], path: int[][], result: int[][][]) {
path.push([row, col])
if ([row, col] is the destination) {
result.add(path)
}
else {
for (direction in each_cardinal_direction) {
new_row = row + direction.row
new_col = col + direction.col
if (in_bounds(new_row) and in_bounds(new_col) and
maze[new_row][new_col] is unvisited) {
maze[row][col] = visited
DFS(new_row, new_col, maze, path, result)
maze[row][col] = unvisited
}
}
}
path.pop()
}
我不是很清楚你为什么同时使用显式和隐式状态;通常,当 运行 和 DFS 时,使用显式堆栈和 while
循环或使用递归并将所有状态存储为调用堆栈上的帧。考虑改进命名清晰度、设计和 spacing/indentation,以便您的逻辑更容易理解。
例如,str
是一个充当堆栈的数组,应该这样命名,而您的 stack
class 实际上根本不是堆栈,而是而是一个迷宫求解器。您的 pop
函数不准确,一次只能删除一个元素。
此外,由于您使用的是 C++ classes 和字符串,您也可以利用容器。
这是一个临时修改迷宫的递归示例,添加墙壁以标记访问过的节点以避免循环:
#include <iostream>
#include <vector>
void DFS(
int row, int col,
std::vector<std::vector<char>> &maze,
std::vector<std::pair<int, int>> &path,
std::vector<std::vector<std::pair<int, int>>> &result
) {
path.push_back(std::make_pair(row, col));
if (maze[row][col] == 'e') {
result.push_back(path);
}
else {
int dirs[][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
for (auto d : dirs) {
int r = d[0] + row;
int c = d[1] + col;
if (r >= 0 && c >= 0 && r < maze.size() &&
c < maze[r].size() && maze[r][c] != '*') {
maze[row][col] = '*';
DFS(r, c, maze, path, result);
maze[row][col] = '-';
}
}
}
path.pop_back();
}
std::vector<std::vector<std::pair<int, int>>>
getPaths(std::vector<std::vector<char>> maze) {
std::vector<std::vector<std::pair<int, int>>> result;
std::vector<std::pair<int, int>> path;
int row = -1;
int col = -1;
for (int i = 0; i < maze.size() && row == -1; i++) {
for (int j = 0; j < maze[i].size() && col == -1; j++) {
if (maze[i][j] == 's') {
row = i;
col = j;
}
}
}
DFS(row, col, maze, path, result);
return result;
}
int main() {
std::string raw = "s-----\n*-*-*-\n*-e-*-\n**-**-\n**----";
std::vector<std::vector<char>> maze;
std::vector<char> row;
for (int i = 0; i < raw.size(); i++) {
if (raw[i] == '\n') {
maze.push_back(row);
row.clear();
}
else {
row.push_back(raw[i]);
}
}
maze.push_back(row);
for (auto &path : getPaths(maze)) {
std::cout << std::endl << '[';
for (auto &cell : path) {
std::cout << '(' << cell.first <<
"," << cell.second << ')';
}
std::cout << ']' << std::endl;
}
}
输出:
[(0,0)(0,1)(0,2)(0,3)(0,4)(0,5)(1,5)(2,5)(3,5)(4,5)(4,4)(4,3)(4,2)(3,2)(2,2)]
[(0,0)(0,1)(0,2)(0,3)(1,3)(2,3)(2,2)]
[(0,0)(0,1)(1,1)(2,1)(2,2)]