问题
Given a source and a destination cell in a maze, I would like to find all possible solutions to a maze using DFS. 0 represents a wall in my maze.
Visualise the maze
I've successfully written a program, but that gives me only one path. I've thought of all the possibilities to extend it to all paths but sadly even after being hours(2 days to be precise) at it, I was unable to come up with a solution.
I thought of keeping a "visited" array for each node so that when I backtrack I don't perform the same move for the previous node. However doing that would only produce a path that is completely distinct(if there is any) with no nodes being the same.
I also thought of some other way but even that posed some problem.
I've also checked out similar questions but none of them are specific to my context. There is a solution using explicit recursion. However, what I want is to use a stack and find all possible paths. Sadly, I couldn't find anything credible(at least in a way that I could understand).
Here's my code for one path.
Edit: I've now implemented the "proper" DFS. I've also added a stack to keep track of the current path. The program then also checks for the unexplored nodes. However, its checking in some other order and therefore I still can get only one path!
#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;
}
Can someone please guide me to modify this code such that it finds all paths. Expecting the community's help!
PS: SO currently doesn't allow me to embed images and therefore it has automatically created a link.
PS: This question has been marked as duplicate relating to some other question. For your information, I had gone through that very question before posting my question! If anyone would have read the answer there, you could see it wasn't "accepted"! It just says you need to do "all" permutations! If only one would have bothered to go through the other answer(in the other question), they would have realised that it only applied to moving in north, northeast, or east directions! Moreover, I also had made it pretty clear that I don't want a recursive solution - that's what the other question was using!
Edit 2: Working solution
#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;
}
回答1:
I think you need to clear the corresponding field in visited where you remove the point from the stack.
Edit: Another issue is that you need to backtrack when you have reached the goal. And on your stack, it's probably not obvious what unexplored alternatives are and what the current path is (you might be able to use the visited array to track this, but it seems more convoluted than "just" using recursion or adding the corresponding information to your Stack stuct)
Also, subsequent nodes should be marked visited when they are actually investigated, not when they are pushed on the stack.
Some remarks
I think the code would be more readable using recursion instead of an explicit stack
You don't really need visited, you could just change maze fields on the path to 1 temporarily (probably wouldn't do this in "real" code where the maze should be immutable though). Otherwise, I'd just structure it the same way as the maze.
I'd change push to take a point for symmetry.
Avoid redundancies bloating the code. For instance, the
front == NULL
branch inpush
is redundant with the default case -- the default case will do exactly the same thing in the NULL case.
Edit 2:
If you really want to avoid recursion, I'd change the data structure to this:
typedef struct PathElement {
int x;
int y;
int direction_to_next;
struct PathElement* next;
struct PathElement* prev;
} path;
This will allow you to easily go in any direction (for instance, you'll be at the end of a path when you want to print). When you backtrack to a PathElement, increment direction_to_next and continue there until you have exhausted all 4 possible directions. Don't "push" alternatives ahead of time.
回答2:
For each point in your search, keep a reference to the predecessor point. Always pop the item off your stack after operating on it. Note that if there is no solution, your code will infinite loop. And when you get to the end, you can use the predecessors to backtrack and find the full path.
Get rid of your visited array, and to prevent cycles during the DFS, check to make sure the point you are adding to the path is not currently in the path. Since you only have 30 possible points in your maze, you could use a bitfield to denote whether the a given point is in the path.
Also, don't break out of the loop prematurely (upon finding the first available move).
来源:https://stackoverflow.com/questions/46817353/find-all-paths-in-a-maze-using-dfs