迷宫求解!

来源:互联网 发布:淘宝怎么搜店铺 编辑:程序博客网 时间:2024/04/29 18:03

问题:从迷宫的入口找到通向出口的路径。

 

算法:为了描述迷宫的布局,将定义迷宫的数组m[][]设为全局变量以减少形参传递。另外还需要一个结构体来描述迷宫足迹的坐标,定义如下:

    struct Maze_Location

{  int x;   //行坐标

   int y;   //列坐标};

int cur_num为记录通道的编号变量,每当有一个可走的通道时,cur_num就加1,最终找到一条路径的时候,该路径的呈现方式是1,2,3,4............依次按编号连成的一条线。刚开始还需设定入口和出门的坐标,并且入口坐标对应的块应该(确切的说是必须)为通道块,因此先将该坐标对应的位置上赋值为1,即cur_num当前的初始编号。为迷宫设定通道块和墙(通道块对应的值是-1,墙为0)程序的大体流程如下:

按(由东---北)的方向寻找路径

{

   若下一步是通道块,则

                                          {

                                             编号加1,并且赋值给下一步足迹块;

                                                     若此时的这一步的坐标为出口坐标

                                                              {直接打印出路径;(一条路径已经找到!)}

                                                     否则

                                                            {递归调用该算法,但是此时的参数有变化,参数为当前这一步的坐标与当前编号(每次递归的参数都是下一步)}

                                                     编号减1;

                                                    将该块的值恢复为-1;

                                          }

}

void  FindPath(Maze_Location curpos,int cur_num)
{   int i;
   Maze_Location next;
   Maze_Location direction[4]={{0,1},{-1,0},{0,-1},{1,0}};//改变方向
    for (i=0;i<=3;i++)
    {
  next.x=curpos.x+direction[i].x;
  next.y=curpos.y+direction[i].y;
  if (m[next.x][next.y]==-1)                  //若是通道块
  {
   m[next.x][next.y]=++cur_num;       //编号+1
      if (next.x!=ending.x || next.y!=ending.y)//下一步的坐标只要不是出口坐标就继续递归
        FindPath(next,cur_num);
   else
   {
     print();
     printf("\n");
   }
       m[next.x][next.y]=-1;   
      cur_num--;
  }
    }
}        

程序如下:

#include "c1.h"#define MAXLENTH 5struct Maze_Location{int x;int y;};typedef int Maze[MAXLENTH][MAXLENTH];Maze m;  //创建迷宫m,定义为全局变量减少形参Maze_Location start,ending;//入口坐标、出口坐标int cur_num=1;   //初始化序号//子函数开始void print(){   int i,j;for(i=0;i<MAXLENTH;i++){for (j=0;j<MAXLENTH;j++)printf("%3d",m[i][j]);printf("\n");}}void InitMaze(int k){   int i,n,j,x1,y1;    for (i=0;i<MAXLENTH;i++)    m[0][i]=m[i][0]=m[MAXLENTH-1][i]=m[i][MAXLENTH-1]=0;//四周值为0,0代表墙    printf("请输入你想要布置迷宫除内的墙的个数:\n");    scanf("%d",&n);    for (i=1;i<MAXLENTH-1;i++){    for (j=1;j<MAXLENTH-1;j++)m[i][j]=k;//先置迷宫内部全为1,即全是通道}printf("现在开始为迷宫布置墙,请依次输入迷宫内的墙的坐标:(行列均从0开始)\n");for(j=1;j<=n;j++)//布n堵墙{scanf("%d,%d",&x1,&y1);m[x1][y1]=0;}print();//打印迷宫printf("请输入入口坐标:\n");scanf("%d,%d",&start.x,&start.y);printf("请输入出口坐标:\n");scanf("%d,%d",&ending.x,&ending.y);}void  FindPath(Maze_Location curpos,int cur_num){   int i;Maze_Location next;Maze_Location direction[4]={{0,1},{-1,0},{0,-1},{1,0}};//注意东就是列加1行不变,而数组中对应的就是Y加1    for (i=0;i<=3;i++)    {next.x=curpos.x+direction[i].x;next.y=curpos.y+direction[i].y;if (m[next.x][next.y]==-1){m[next.x][next.y]=++cur_num;    if (next.x!=ending.x || next.y!=ending.y)      FindPath(next,cur_num);//只要没有到出口就继续寻找else{  print();  printf("\n");}            m[next.x][next.y]=-1;//一下两句很重要,若走的块是通道块但却没有其他出路,即只能原路返回,这时    cur_num--;           //就要把之前给这个块赋的编号取消,恢复为-1}    }}void main(){InitMaze(-1);m[start.x][start.y]=1;printf("迷宫的路径如下:\n");FindPath(start,cur_num);}

 


此算法很好理解,但有一点不好理解,我想了很久,即如下情形:

                                                0   0  0  0

                                               -1  -1  0  0 

                                               0   0   0  0

假设红色部分为现在的足迹,现在开始要往东走,我们大眼一看就知道其实不能往东走,因为下一步尽管是通道块,但是它是个死胡同,没有办法寻找下个路径了,它只能返回原来的路径。但是这在程序里怎么体现呢?这个我想了很久,就是上面的最后两句:

                                                                 m[next.x][next.y]=-1;

                                                                 cur_num--;

当足迹有第一个红色-1出走到下一个-1时,首先发现它是通道块,编为它进行编号(假设是序号2),如下:

                                               0   0  0  0

                                              1   2  0  0 

                                               0   0   0  0

 

发现此时的这个-1(序号2)通道除了原方向没有路可走了,那么就要返回,可是如果你直接返回的话那么下次还是会来到这里,这样就陷入死循环了,所以要取消它的编号,让它恢复为普通的通道块,序号同时也减1(用以给别的块赋值)。此时不用担心还会遇见这个死胡同了,因为这时已经到了程序的结尾了,该在红色1处的足迹上进行下一个for循环了,即换方向了。

原创粉丝点击