迷宫问题探讨!
1.搜索空间问题.
对于一个66的迷宫,它的搜索空间是多少?
66=36个格子, 每一格的可能搜索方向是4个
根据乘法原理它最大的搜索空间是4^36次方,
这是一个很大的搜索空间,实际上搜索远小于此数.因为搜索的时候
只会沿着通路搜索, 墙被过滤掉了, 搜索空间显著的减小.
2.何为搜索.
搜索就是从庞大的搜索空间中找到一个或全部符合条件的解的过程.
这是搜索广义的概念.
计算机搜索可以理解成构建一个数组的过程,而构建过程为搜索算法.
3.迷宫的表示方法.
迷宫可以用一个2维数组来表示, 0为通路,1为墙.
从入口entry(x1,y1), 找到出口export(x2,y2)的路径为其一个解.
如果找到了一个解,可以把路径中的数值改为2来输出这个2维数组.
4.怎样表示找到了一个解,怎样表示一个搜索路径?
当从入口entry(x1,y1)开始, 依据通道(其值为0)不断搜素,改变x1,y1的值,
当x=x2, y=y2时,表示找到了出口.代表找到了一个解.
找到解后, 必须要根据一个链表,追溯到它的起点, 这个链表就是一个路径.
5.本示例的搜索算法是怎样的?
算法描述: 采用了一个通道队列.
- 首先, 入口入队列,
- 然后, 循环执行
从队列尾部取出一个点, 把它周围的通道(最多三个,最少0个)放入到队列头部 - 结果判断,
这样,当iQueuetail 追上iQueueHead 时,表示搜索结束,没有路径.
或者iQueueHead 找到了出口,输出结果,
找到结果后,可以停止搜索,或继续搜索.
这属于一种宽度优先的搜索算法.
6.代码实例:
#include <stdio.h>
#include <stdlib.h>
#define ROW 15
#define COLUMN 21
/* 定义四周为墙。故为ROW+2,COLUMN+2, 0 为通路,1为墙,-1为搜索过,2为通路路径 */
int gMaze[ROW+2][COLUMN+2]=
{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1},
{1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1},
{1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
};
typedef struct{
int i,j; /*4个搜索方向的坐标变化值 */
}Direction;
// 左右上下,注意,此处列值移动为左右,行值移动为上下,直接与MAZE 数组下标运算
Direction gDirect[4]={{0,-1},{0,1},{-1,0},{1,0}};
typedef struct{
int x,y; /*搜索位置的坐标 */
int pre; /*表示前驱点的数组位置索引,所有的脚步构成一个数组 */
}Footstep;
#define MAX 500
Footstep gFoots[MAX]; //定义500个脚步数组
void print_result(int tail)
{
int i,j,k;
k=tail;
do
{
i=gFoots[k].x; j=gFoots[k].y;
gMaze[i][j]=2; // 2 代表是通路路径
k=gFoots[k].pre; // 由后继找到它的前趋。
}while(k); // 在2维数组中建立一条搜索通路
/*
for(i=1;i<=k;i++)
{
gMaze[gFoots[i].x][gFoots[i].y]=2;
}
*/
printf("模拟迷宫路径:'>' 表示最后走出迷宫的路径, '@'表示探索过的路径\n");
printf("进入--\n");
for (i=1;i<=ROW;i++)
{
for (j=1;j<=COLUMN;j++)
{
if (gMaze[i][j]==2) printf("%2c",'>');
else if(gMaze[i][j]==-1) printf("%2c",'@');
else printf("%2d",gMaze[i][j]);
}
if (i==ROW) printf("--走出\n\n");
else printf("\n\n");
}
}
/* 算法描述: 采用了一个通道队列.
* 首先, 入口入队列,
* 然后 循环执行
* 从队列尾部取出一个点, 把它周围的通道
* 最多三个,最少0个继续放入到队列头部,然后循环处理尾部点.
* 这样处理结果是,当iQueuetail 追上iQueueHead 时,表示搜索结束,没有路径.
* 或者iQueueHead 找到了出口,根据其前趋,形成路径,输出结果,
* 找到结果后,可以停止搜索,或继续搜索.
* 这属于一种宽度优先的搜索算法.
*/
int main(void)
{
int i,j,k,newi,newj;
int Gotit=0;
int iQueueTail=0;
int iQueueHead=1; //ensure gFoots[0] is 0
//入口入队列(1,1)
gFoots[iQueueHead].x=1;gFoots[iQueueHead].y=1;gFoots[iQueueHead].pre=0;
gMaze[1][1]=-1; //代表(1,1)已经搜索过
do {
/* 下一步出队列, 从队列中取出一个通道点.
* iQueueTail 跟随iQueueHead的脚步,在其基础上继续搜索.
* 直到找到出口.
*/
iQueueTail++; //尾索引加1,处理下一个结点
i=gFoots[iQueueTail].x; j=gFoots[iQueueTail].y;
if(i==15&& j==21)
{
printf("%d,%d\n",i,j); // for debug
}
for (k=0;k<4;k++){ /*沿4个方向搜索*/
newi=i+gDirect[k].i; newj=j+gDirect[k].j; /*确定新的搜索位置 */
/*如果新位置是未搜索通道,则将新位置入队列
* 如果是墙,继续搜索其它.
* 如果曾经搜索过,也继续搜索其它,防止回退.
* */
if (!gMaze[newi][newj]) {
iQueueHead++; //头索引加1
gFoots[iQueueHead].x=newi; //保存矩阵的x,y坐标值
gFoots[iQueueHead].y=newj;
gFoots[iQueueHead].pre=iQueueTail; // 标识新结点的前趋
gMaze[newi][newj]=-1; /*标识搜索过的位置为-1, 来了就算搜索过*/
}
if (newi==ROW && newj==COLUMN){ /*判断是否是出口*/
print_result(iQueueHead);
Gotit=1;
break; // pay attention, 找到一个出口即可.
}
}
}while(iQueueTail<iQueueHead); // 未搜索完,继续
if (!Gotit) printf("No Pass!\n");
return 0;
}