鉴于迷宫中的源和目标单元格,我想使用DFS找到所有可能的迷宫解决方案。 0表示我迷宫中的墙。
我已经成功编写了一个程序,但这只给了我一个路径。我已经想到了将它扩展到所有路径的所有可能性,但遗憾的是,即使经过数小时(确切地说是2天),我也无法找到解决方案。< / p>
我想要保持一个&#34;访问&#34; 每个节点的数组,这样当我回溯时,我不会为前一个节点执行相同的移动。但是,这样做只会产生一个完全不同的路径(如果有的话)没有相同的节点。
我还想到了其他一些方法,但即使这样也会产生一些问题。
我也检查了类似的问题,但没有一个是具体到我的上下文中。有一个使用显式递归的解决方案。但是,我想要的是使用堆栈并找到所有可能的路径。可悲的是,我找不到任何可信的东西(至少以我能理解的方式)。
这是一个路径的代码。
编辑:我现在已经实施了&#34;正确的&#34; DFS。我还添加了一个堆栈来跟踪当前路径。然后程序还会检查未探测的节点。但是,它以其他顺序检查,因此我仍然只能获得一条路径!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Point
{
int x,y;
}Point;
typedef struct stack
{
struct Point pt;
struct stack* next;
void push(int, int);
Point pop();
}stack, stack_path;
stack*front =NULL;
stack_path*front_path =NULL;
void push(int x, int y)
{
if(front==NULL)
{
front = (stack*)malloc(sizeof(stack));
front -> pt.x = x; front -> pt.y = y;
front -> next = NULL;
return;
}
stack* temp = (stack*)malloc(sizeof(stack));
temp -> pt.x = x; temp -> pt.y = y;
temp -> next = front;
front = temp;
}
Point pop()
{
if(front != NULL)
{
stack* temp = front;
Point pt = front -> pt;
front = front -> next;
free(temp);
return pt;
}
}
void push_path(int x, int y)
{
if(front_path==NULL)
{
front_path = (stack*)malloc(sizeof(stack_path));
front_path -> pt.x = x; front_path -> pt.y = y;
front_path -> next = NULL;
return;
}
stack_path* temp = (stack*)malloc(sizeof(stack_path));
temp -> pt.x = x; temp -> pt.y = y;
temp -> next = front_path;
front_path = temp;
}
Point pop_path()
{
if(front_path != NULL)
{
stack_path* temp = front_path;
Point pt = front_path -> pt;
front_path = front_path -> next;
free(temp);
return pt;
}
}
bool inMaze(Point pt)
{
return (pt.x>=0 && pt.y>=0 && pt.x<5 && pt.y<6);
}
int main()
{
struct Point pt1;
int visited[30]={0};
push(0,0);
push_path(0,0);
struct Point dest = {3,4};
int maze[5][6] = {{1,0,1,1,1,1},
{1,0,1,0,1,1},
{1,1,1,0,1,1},
{0,0,0,0,1,0},
{1,1,1,0,1,1}};
int paths[30]={0};
int dx[4]={-1, 0, 0, 1};
int dy[4]={0,-1, 1, 0};
while(front!=NULL)
{
Point pt = pop();
if(pt.x==dest.x && pt.y==dest.y)
{
push_path(pt.x,pt.y);
int i;
visited[6*pt.x+pt.y] = 0;
stack_path *temp = front_path;
while(temp!=NULL)
{
printf("%d%d ",temp->pt.x, temp->pt.y);
temp = temp->next;
}
printf("\n");
pop_path();
}
else
{
if(!visited[6*pt.x+pt.y])
{
visited[6*pt.x+pt.y] = 1;
push_path(pt.x,pt.y);
}
int i;
int flag =0;
for(i=0; i<4; i++)
{
pt1.x = dx[i] + pt.x;
pt1.y = dy[i] + pt.y;
if(inMaze(pt1) && maze[pt1.x][pt1.y]==1 && visited[6*pt1.x+ pt1.y]==0)
{
push(pt1.x,pt1.y);
flag = 1;
}
}
if(flag==0)
pop_path();
}
}
return 0;
}
有人可以指导我修改此代码,以便找到所有路径。期待社区的帮助!
PS:因此目前不允许我嵌入图片,因此它会自动创建一个链接。
PS:此问题已被标记为与其他一些问题相关的重复。为了您的信息,我在发布问题之前已经完成了这个问题!如果有人会在那里阅读答案,你可以看到它不是&#34;接受&#34; !它只是说你需要做&#34;所有&#34; 排列!如果只有一个人会打扰通过另一个答案(在另一个问题中),他们会意识到仅应用来向北,东北或东方方向移动!此外,我还明确表示我不想要一个递归解决方案 - 这是另一个问题所使用的内容!
编辑2 工作解决方案
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Point
{
int x,y;
}Point;
typedef struct stack
{
struct Point pt;
struct stack* next;
int dir_count;
}stack;
stack*front =NULL;
void push(int x, int y)
{
stack* temp = (stack*)malloc(sizeof(stack));
temp -> pt.x = x; temp -> pt.y = y;
temp -> next = front;
front = temp;
}
Point pop()
{
if(front != NULL)
{
stack* temp = front;
Point pt = front -> pt;
front = front -> next;
free(temp);
return pt;
}
}
bool inMaze(Point pt)
{
return (pt.x>=0 && pt.y>=0 && pt.x<5 && pt.y<6);
}
int main()
{
struct Point pt1,pt2;
struct Point pt = {0,0};
push(0,0);
front->dir_count = 0;
struct Point dest = {3,4};
int maze[5][6] = {{1,0,1,1,1,1},{1,0,1,0,1,1},{1,1,1,0,1,1},{0,0,0,0,1,0},{1,1,1,0,1,1}};
int dx[4]={-1, 0, 0, 1};
int dy[4]={0,-1, 1, 0};
int flag_pop = 0;
while(front != NULL)
{
if(front->pt.x==dest.x && front->pt.y==dest.y)
{
stack* temp = front;
while(temp != NULL)
{
printf("%d%d ", temp->pt.x, temp->pt.y);
temp = temp->next;
}
printf("\n");
pt = pop();
}
else
{
int i,k;
int flag_push =0, count = 0, moves=0;
for(k=0;k<4;k++)
{
pt2.x = dx[k] + front->pt.x;
pt2.y = dy[k] + front->pt.y;
if(maze[pt2.x][pt2.y]==0 || !inMaze(pt2) || !(pt.x != pt2.x || pt.y != pt2.y))
count++;
}
// count of possible moves for each node
moves = 4-count;
for(i=0; i<4; i++)
{
int flag=0;
pt1.x = dx[i] + front->pt.x;
pt1.y = dy[i] + front->pt.y;
// if moves are exhausted
if(!(front->dir_count<moves))
break;
if(inMaze(pt1) && maze[pt1.x][pt1.y]==1 && (pt.x != pt1.x || pt.y != pt1.y) )
{
stack* temp = front;
while(temp != NULL)
{
if(temp->pt.x == pt1.x && temp->pt.y == pt1.y)
{
flag = 1;
break;
}
temp = temp->next;
}
// if node is not there in the path
if(flag==0)
{
front->dir_count++;
push(pt1.x, pt1.y);
front -> dir_count = 0;
flag_push = 1;
break;
}
}
}
// if no move was done
if(flag_push==0)
{
pt = pop();
}
}
}
return 0;
}
答案 0 :(得分:1)
我认为您需要清除访问中的相应字段,从堆栈中删除该点。
修改:另一个问题是,当您达到目标时需要回溯。在您的堆栈上,可能并不明显未开发的替代方案是什么以及当前路径是什么(您可能能够使用被访问的数组来跟踪它,但它似乎比使用递归或添加相应信息的“仅仅”更复杂。你的Stack stuct)
此外,后续节点在实际调查时应标记为已访问,而不是在将它们推入堆栈时。
一些评论
我认为代码使用递归而不是显式堆栈更具可读性
你真的不需要访问,你可以暂时将路径上的迷宫字段更改为1(可能不会在迷宫应该是不可变的“真实”代码中执行此操作)。否则,我只是以与迷宫相同的方式构建它。
我会改变推动,以便采取对称的方式。
避免冗余膨胀代码。例如,front == NULL
中的push
分支在默认情况下是多余的 - 默认情况下在NULL情况下会完全相同。
编辑2 :
如果你真的想避免递归,我会将数据结构更改为:
typedef struct PathElement {
int x;
int y;
int direction_to_next;
struct PathElement* next;
struct PathElement* prev;
} path;
这将允许您轻松地向任何方向前进(例如,当您想要打印时,您将位于路径的末尾)。当你回溯到PathElement时,增加direction_to_next并继续那里直到你已经用完所有4个可能的方向。不要提前“推”替代品。
答案 1 :(得分:0)
对于搜索中的每个点,请保留对前一点的引用。操作后,始终将物品从堆叠中弹出。 请注意,如果没有解决方案,您的代码将无限循环。当你走到最后,你可以使用前辈来回溯并找到完整的路径。
摆脱被访问的数组,并防止在DFS期间出现循环,检查以确保添加到路径中的点当前不在路径中。由于迷宫中只有30个可能的点,因此可以使用位域来表示给定点是否在路径中。
此外,不要过早地突破循环(在找到第一个可用的移动时)。