c解决迷宫问题

本文介绍了一种使用栈数据结构解决迷宫问题的方法。通过深度优先搜索策略,从迷宫入口到出口寻找一条可行路径。文章详细展示了算法的实现过程及代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:

在迷宫中求从入口到出口的一条简单路径。迷宫可用方块来表示, 每个方块或者是通道(用空白方块表示)或者是墙(用带阴影的方块表示)。 “迷宫求解”这个经典的问题,应用栈这种数据结构,自己设计一个方案, 并上机实现从入口到出口的一条简单路径。为了表示迷宫,用二维数组表示,如

int a[10][8]={{1,1,1,1,1,1,1,1},
                  {1,0,1,1,0,1,0,1},
                  {1,0,1,0,0,1,0,1},
                  {1,1,0,3,1,0,1,1},
                  {1,0,0,1,0,0,4,1},
                  {1,0,0,0,0,1,1,1},
                  {1,0,1,0,0,1,0,1},
                  {1,0,1,0,0,0,1,1},
                  {1,1,1,1,0,0,0,1},
                  {1,1,1,1,1,1,1,1}
                  };

3是入口,4是出口。

如下链接,可以查看更多详细信息。

http://jpkc.onlinesjtu.com/CourseShare/datastructure/TypicalArithmeticMain.aspx

参照网上一般思路:

在求解时,通常用的是穷举求解的方法,即从入口出发,顺某一方向向前试探,若能走通,则继续往前走;否则沿原路退回,换一个方向再继续试探,直至所有可能的通路都试探完为止。为了保证在任何位置上都能沿原路退回(称为回溯),需要用一个后进先出的栈来保存从入口到当前位置的路径。

我的理解:

用栈保存走过的路线,每个节点的数据又设为元素节点,包含横纵坐标信息,还有到达下一步的方向信息。如下所示

typedef struct{

  int x;

  int y;

  int direction; 

  }node;

为了方便计算下一步的方向,用1,2,3,4表示左上右下,这样用变量自增就可得到下一步的方向。

node step[4]= {{0,-1,1},{-1,0,2},{0,1,3},{1,0,4}};//往左上右下的基坐标



具体思路:

其实这就是一个深度优先遍历的思想。

1.S走到A,即S入栈,并把如何到A的方式记录下来。当前位置设为A,下一步未知设为B。怎么到达B?

2.从A的左上右下四个方向开始试探。

if(找到一个方向可以走通且这个方向之前没有被试探过,就可以从这个方向进入B)

A入栈,并把这个方向存到A中,把B设为已访问。

else (如果找遍四个方向都行不通)

那么就把当前位置A回退到上一步S,并把A还原为未访问。由于S中保存了到A的方向,只要从到A的方向的下一个方向开始继续试探,得出怎么到A,再从这个A开始到B.进入2.知道达到出口程序结束循环。


具体代码如下:

#include "stdio.h"
#include "stdlib.h"
#define  MAXSIZE 200
#define LINES 10 // 定义行数
#define COLS 8 // 定义列数
 typedef struct{
 	int x;
 	int y;
 	int direction; 
  }node;
 typedef struct{
   node data[MAXSIZE];
   int top;
  }SeqStack,*PSeqStack;
 

PSeqStack Init_SeqStack()//初始化栈 
{
    PSeqStack S;
    S = (PSeqStack)malloc(sizeof(SeqStack));
    if(S)
    {
     S->top = -1;
    }
    return S;
 }
int Empty_SeqStack(PSeqStack S)//判栈空 
{
    if(S->top == -1)
     return 1;
     else return 0;
 } 
int Push(PSeqStack S, int x, int y,int a)//入栈 
{
    if(S->top == MAXSIZE -1)
    return 0;
    else
    {
       S->top++;
       S->data[S->top].direction = a;
       S->data[S->top].y = y;
  	   S->data[S->top].x = x;
       return 1; 
    }    
} 
int Pop(PSeqStack S, int *x, int *y, int *a)//出栈 
{
    if(Empty_SeqStack(S)) 
    return 0;
    else 
    {
       *x = S->data[S->top].x;
       *y = S->data[S->top].y;
       *a = S->data[S->top].direction;
       S->top--; 
       return 1;
    }
} 
void Destroy_SeqStack (PSeqStack * SeqStackPoint)
    {/*销毁顺序栈,入口参数:为要销毁的顺序栈指针地址*/
          if (*SeqStackPoint)      free (*SeqStackPoint) ;
          *SeqStackPoint =NULL;
          return ;
    }


void visit(PSeqStack P)
{
	int i,x,y,dir;
	while(!Empty_SeqStack(P))
	{
		Pop(P,&x,&y,&dir);
		printf("(%d,%d,%d)\n",x,y,dir);
	}
}

int maze(int a[LINES][COLS])
{
    int find,x,y,i,j,dir,xx,yy,xs,ys,xxx,yyy,dirr,xxxx,yyyy,dir0;
	node step[4]= {{0,-1,1},{-1,0,2},{0,1,3},{1,0,4}};//往左上右下的基坐标 
    PSeqStack S;
    
    S=Init_SeqStack();
        
    for(i = 0; i < LINES; i++)//获取入口坐标 
    for(j = 0; j < COLS; j++)
    {
     if(a[i][j] == 3) 
     {
        x = i;
        y = j; 
        break;   
     }
    } 
      
    Push(S,x,y,-1);//入口进栈 ,并将方向设为-1,表示不知道下一步的方向是多少,具体值需要下面确定,然后再放入栈中。 
	a[x][y] = -1;//访问入口 ,-1表示当前位置已经访问。1表示墙壁,0表示可行,3是入口,4是出口。 
	while(!Empty_SeqStack(S) )
     {    
	  /*  Pop(S,&xx,&yy,&dir0); //为了得到当前栈顶的数据 。这种方式浪费时间 ,采用下面的读取栈顶元素的值合适 。 
	    x = xx;
	    y = yy;
	    Push(S,xx,yy,dir0);*/ 
	    x = S->data[S->top].x;
        y = S->data[S->top].y;
        dir = S->data[S->top].direction;
	  printf("\nstack top element:(%d,%d,%d)",x,y,dir);
	       
     //走下一步B 
    	 find = 0;
		//dir = -1;//从当前位置的左上右下开始。不能设置为-1,因为下面的回退一步,需要从上一个可行的方向开始自增。 
       	printf("\ntest the direction: ");
		while(!find && dir < 3)
	   {
		dir++;
		printf("%d ",dir);
		switch(dir)
		{
			case 0:xs = x + step[dir].x; ys = y + step[dir].y;break;
			case 1:xs = x + step[dir].x; ys = y + step[dir].y;break;
			case 2:xs = x + step[dir].x; ys = y + step[dir].y;break;
			case 3:xs = x + step[dir].x; ys = y + step[dir].y;break;
		}
		if((a[xs][ys] == 0) ||(a[xs][ys] == 4)) find = 1;	
	   }	 
		if(find == 1)//找到了下一个可走位置, A到B可走 
		{
		 Pop(S,&xxxx,&yyyy,&dirr); 
	     Push(S,xxxx,yyyy,dir);
	    printf("changedir: %d ",dir);
	     Push(S,xs,ys,-1);//A入栈 
	     if(a[xs][ys] == 0)
		 a[xs][ys] = -1;//设当前位置B访问过,-1表示访问过,
		 else  //若该位置是出口,则算法结束 
         {
		 	printf("\nthe reverse of simple rount:\n"); 
            visit(S); 
         	Destroy_SeqStack (&S);
         	return 1;  
		 }
		} 
	   	else //当前位置的下一步不可通过(当前位置为墙壁或者已经访问过) 
	    {
		 a[x][y] = 0;//还原当前位置为未访问 
		//Pop(S,&xxx,&yyy,&dirr);//删去栈顶位置.但是需要变量存储栈顶元素,浪费空间。不妨直接退栈,采用下面的方式。 
		 S->top--;//回退一步 
     	}
	 }
	    
     
    if(Empty_SeqStack(S) )
    {
        printf("sorry");
        Destroy_SeqStack (&S);
        return 0;
    } 
  } 

void main()
{
    int a[10][8]={{1,1,1,1,1,1,1,1},
                  {1,0,1,1,0,1,0,1},
                  {1,0,1,0,0,1,0,1},
                  {1,1,0,3,1,0,1,1},
                  {1,0,0,1,0,0,4,1},
                  {1,0,0,0,0,1,1,1},
                  {1,0,1,0,0,1,0,1},
                  {1,0,1,0,0,0,1,1},
                  {1,1,1,1,0,0,0,1},
                  {1,1,1,1,1,1,1,1}
                  };
    maze(a);
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值