问题描述:给定一个迷宫,给定入口和出口,找到从入口到出口的一条路径(任何一条路径都可以),迷宫为0表示可走,为1表示墙。用1将迷宫围起来避免边界问题。
 实现思路:1.DFS搜索(递归)
 2.采用栈的数据结构
 下面分别用这两种方法来解决这个问题。
 DFS搜索(即递归+回溯)
 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#define ROW 9
#define COL 9int integer[ROW][COL]={     {1,0,1,1,1,1,1,1,1},{1,0,1,1,1,0,0,0,1},{1,0,0,0,0,0,1,0,1},{1,0,1,1,1,0,1,0,1},{1,0,1,0,0,0,1,0,1},{1,0,1,1,1,0,1,0,1},{1,0,0,0,0,1,1,0,1},{1,0,1,1,1,1,1,0,0},{1,1,1,1,1,1,1,1,1}
};
int  print(int integer[ROW][COL],int x,int y);int dir[4][2]={
{1,0},{-1,0},
{0,1},{0,-1},
}  ;     int visted[120][120] ;    int check(int x,int y) 
{if(x< 0 || y<0 || x>= ROW || y>= COL)  return 0;if(visted[x][y])return 0;if(integer[x][y] !=  0 )return 0;return 1;
}int dfs(int x,int y)    
{int xx,yy ,i ;usleep(100000);printf("\033c");print(integer,x,y);if(x ==  7 && y == 8 )exit(0);for(i= 0;i< 4 ;i++)   {xx =  x + dir[i][0];yy =  y + dir[i][1];if(check(xx,yy))    {visted[xx][yy]= 1;dfs(xx,yy) ;visted[xx][yy] = 0 ;  }}usleep(100000); printf("\033c");print(integer,x,y);return 0;
}int print(int integer[ROW][COL],int x,int y)
{int i,j;for(i=0;i<ROW ;i++){for(j=0 ;j<COL ;j++){if(visted[i][j])printf("\033[41;32m  *  \033[0m") ;else printf("  %d  ",integer[i][j]);}printf("\n\n");}
}
int main(void)
{int i,j ;memset(visted,0,sizeof(visted));visted[0][1]=1;      dfs(0,1) ; 
}
 运行截图:
 
 PS 1.这是一个动态演示的程序,可以清晰的看到移动的动作,所以运行有奇效
 2. 回溯之后要再打印一次,才能有回溯的效果,并且必须有sleep 函数,否则会因为程序运行太快而导致看不到回溯的效果。
 3. 如果对于DFS搜索还不太懂的–>点这里,文中提到的马踏棋盘我会在下一篇博客中提到。
 采用栈的数据结构
 先来提出几个问题
 1.为什么要用栈来实现?有什么好的地方?
2.di 有什么作用?为什么要它?
3.栈空与栈不空,有什么用?
4.大体思路是什么?
 #include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#define  MAXSTACKSIZE  100  
#define      N          10     
#define  Entrance_row   0  
#define  Entrance_col   1 
#define  Exit_row   8   
#define  Exit_col   9
typedef struct position{   int x;int y;
}position ;
typedef struct SElement {position p;   int di;     
}SElement ; 
typedef struct Mystack{SElement  *top;SElement  *base;int stackSize ;
}Mystack ;int Maze[N][N]={{2,0,2,2,2,2,2,2,2,2},{2,0,0,2,0,0,0,2,0,2},{2,0,0,2,0,0,0,2,2,2},{2,0,0,0,0,2,2,0,0,2},{2,0,2,2,2,0,2,0,2,2},{2,0,0,0,2,0,0,0,0,2},{2,0,2,0,0,0,2,0,0,2},{2,0,2,2,2,0,2,2,0,2},{2,2,0,0,0,0,0,0,0,0},{2,2,2,2,2,2,2,2,2,2} 
};int IsEmptyStack(Mystack *path);int InitStack(Mystack *path)   
{path->top = path->base =(SElement *)malloc(sizeof(SElement)*MAXSTACKSIZE);if(path->top == NULL ){printf("Init  stack is failed !!! \n");return -1;}path->stackSize = MAXSTACKSIZE;return 0;
}int pop(Mystack *path ,SElement *t)  
{if(IsEmptyStack(path) == 1)return 0;*t = *(path->top-1);path->top-- ;return 1;
}int push(Mystack *path ,SElement p) 
{*(path->top) = p ;path->top++;
}int IsEmptyStack(Mystack *path)
{if(path->top == path->base )   return 1;  else return 0 ;
}
int print_MAZE(int Maze[N][N])  
{int i,j;for(i= 0 ;i< N;i++){for(j= 0 ;j< N ;j++){if(Maze[i][j] == 10)    printf("\033[31m  *  \033[0m") ;else  printf("  %d  ",Maze[i][j]);}printf("\n\n");}
}
int check(position now_try) 
{if(Maze[now_try.x][now_try.y]  !=  0)  return 0;if(now_try.x <  0 && now_try.x >=  N  )return 0;if(now_try.y <  0 && now_try.y >=  N  )return 0;return 1;
}position   NextPosition(position  now_try ,int direction)  
{position next ;next.x= now_try.x;next.y  = now_try.y;switch(direction){case 4:next.y+=1;break; case 3:next.x+=1;break; case 1:next.x-=1;break;case 2:next.y-=1;break;}return next ;
}
int main(void)
{print_MAZE(Maze) ;Mystack  path ;InitStack(&path);position  now_try ; now_try.x= Entrance_row;now_try.y= Entrance_col;do{if(check(now_try)) {Maze[now_try.x][now_try.y]  =10 ;SElement temp ;temp.p.x= now_try.x;temp.p.y= now_try.y;push(&path,temp);if(now_try.x == Exit_row && now_try.y == Exit_col )break;now_try  = NextPosition(now_try,1);  printf("\033c"); print_MAZE(Maze);usleep(800000);}else     {if(IsEmptyStack(&path) !=  1)  {SElement t ;pop(&path,&t);    while(t.di == 4 && IsEmptyStack(&path) !=  1){   Maze[t.p.x][t.p.y] = 9 ;   pop(&path,&t);}if(t.di < 4) {now_try = NextPosition(t.p,t.di+1);t.di++;push(&path,t);}}}}while( IsEmptyStack(&path) ==  0  );  printf("\033c");print_MAZE(Maze);return 0;
}
 运行截图:
 
 问题解答:
 1.首先我们都知道栈有先进后出的特点,那么我们的迷宫是否需要这种特点呐。如果走的通,那么就走,如果走不通,那是不是要回到前一步,找另外一个方向走。那么前一步怎么存储?是不是符合一个先存后取的顺序!OK !这不正好与我们的栈的特点重合吗。
 2.di 的作用有两个。一是表示方向,二是表示走了几个方向了。是不是感觉很拗口。那么我来简单解释一下。用1,2,3,4来表示东南西北,如果di==3,那么就说明北面还没有走,如果di == 4,那么就说明四个方向都已经走过了。
 3.栈空与栈不空,有什么用?假如我们将迷宫改成了这样,那么会发生什么?
 int Maze[N][N]={{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,0,2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2,2,2} 
};
 是不是会依次入栈,然后依次出栈,出栈之后是不是会栈空,如果不判断栈空的话是不是会陷入一种死循环的状态呐。
 4.核心代码:
     now_try.x= Entrance_row;now_try.y= Entrance_col;do{if(check(now_try)) {Maze[now_try.x][now_try.y]  =10 ;SElement temp ;temp.p.x= now_try.x;temp.p.y= now_try.y;push(&path,temp);if(now_try.x == Exit_row && now_try.y == Exit_col )break;now_try  = NextPosition(now_try,1);  printf("\033c"); print_MAZE(Maze);usleep(800000);}else     {if(IsEmptyStack(&path) !=  1)  {SElement t ;pop(&path,&t);    while(t.di == 4 && IsEmptyStack(&path) !=  1){   Maze[t.p.x][t.p.y] = 9 ;   pop(&path,&t);}if(t.di < 4) {now_try = NextPosition(t.p,t.di+1);t.di++;push(&path,t);}}}}while( IsEmptyStack(&path) ==  0  );  
 大体思路:
 
 参考资料:参考资料