问题
从S出发,每次往东南西北四个方向前进。 如果前方有墙壁,游戏者可以往前推移一格。 如果有连续两堵墙(包含)以上的墙,或者是游戏区域边界上的墙 则推不动。
求最少步数走出迷宫 4行6列,多解时任意输出一格移动序列即可
思路
迷宫怎么存储
用三元组表示一堵墙
数组wallX[y][x1][x2] 表示第y=y时 从x1与x2之间有一堵墙
数组wallY[x][y1][y2] 表示第x=x时 从y1与y2之间有一堵墙
数组wallX wallY 就能刻画迷宫的形状起点S(x, y) 如何判断应走出迷宫
行y[1, 4] 列x[1,6]; 增加虚拟行y=0、5 虚拟列x=0、7
如果能走到 (0, *)|(7, *)|(*,0)|(*,5) 其中任意一个位置 即走出迷宫- 如何保证步数最少
解决迷宫问题 一般都用递归;
用深度优先DFS获取的第一条路径不一定是最短的;
用广度优先BFS,第一条路径肯定是最短的 但需要维护一个队列,存储每走一步后的迷宫状态,很占空间;
如果用迭代加深搜素算法IDA*则能有效解决上述问题,即限定BFS的深度,并依次递增知道找到问题的解
for(depth=1; ;depth++)
DFS(S0); // 限制递归深度最大为depth
if find soulation:
break;
测试案例 & 结果
输入:
x 1 6 7
x 2 0 1
x 2 2 3
x 2 4 5
x 2 6 7
x 3 0 1
x 3 1 2
x 3 2 3
x 3 4 5
x 3 5 6
x 3 6 7
x 4 1 2
x 4 3 4
x 4 5 6
y 1 0 1
y 1 1 2
y 1 3 4
y 1 4 5
y 2 0 1
y 2 2 3
y 2 3 4
y 2 4 5
y 3 0 1
y 3 1 2
y 3 2 3
y 3 4 5
y 4 0 1
y 4 1 2
y 4 2 3
y 4 4 5
y 5 0 1
y 5 2 3
y 5 3 4
y 5 4 5
y 6 0 1
y 6 3 4
y 6 4 5
0 0 0 0
打印图像:
--------
@@_@_@_@_@_@_@@@
@@_@@@_@_@@@@|@@
@|@@_|_@_|_@@|@@
@|_|_|@@@|_|_|@@
@@_|_@_|_@_|_@@@
@@@@@@@@@@@@@@@@
--------
行走路径:
(2 3)
(2 2)
(3 2)
(3 3)
(4 3)
(4 4)
(5 4)
(6 4)
(6 3)
(6 2)
(5 2)
(5 1)
(4 1)
(3 1)
(2 1)
(1 1)
(0 1)
代码
#include <stdio.h>
#include <stdlib.h>
#define MaxDepth 100
//当前允许递归的最大深度
int curMaxDepth;
//保存行走路径
int ansX[MaxDepth], ansY[MaxDepth];
//保存迷宫墙的信息
int wallX[6][8][8], wallY[8][6][6];
// 行走方向 东 南 西 北
int dirX[]={1, 0 , -1, 0}, dirY[]={ 0, 1, 0, -1};
// x、y的最大值
int maxX=7, maxY=5;
// 起点
int beginX=2, beginY=3;
// 打印图像
void showWall()
{
int i,j;
printf("--------\n");
for(j=0; j<6; j++)
{
for(i=0;i<8;i++)
{
if( wallX[j][i][i+1]==1 && wallY[i][j][j+1]==1 )
printf("_|");
else if ( wallX[j][i][i+1]==1 && wallY[i][j][j+1]==0 )
printf("@|");
else if ( wallX[j][i][i+1]==0 && wallY[i][j][j+1]==1 )
printf("_@");
else if ( wallX[j][i][i+1]==0 && wallY[i][j][j+1]==0 )
printf("@@");
}
printf("\n");
}
printf("--------\n");
}
// 找第step步的解
int find(int step)
{
int x, y, nextX, nextY, i, j, k, wallMoved;
x = ansX[step-1];
y = ansY[step-1];
// no solution;
if( step > curMaxDepth ) return 0;
// 四个方向 进行尝试
for(i=0; i<4; i++)
{
nextX = x+dirX[i];
nextY = y+dirY[i];
wallMoved = 0;
// 有墙 && (墙后还是墙||是边界墙) 无解
if( wallX[y][x][nextX] && ( wallX[y][nextX][nextX+dirX[i]] || nextX==0 || nextX==7) )
continue;
if ( wallY[x][y][nextY] && ( wallY[x][nextY][nextY+dirY[i]] || nextY==0 || nextY==5) )
continue;
// 左|右 移动墙壁
if( dirX[i] != 0 && wallX[y][x][nextX])
{
wallMoved = 1;
wallX[y][x][nextX] = 0;
wallX[y][nextX][x] = 0;
wallX[y][nextX][nextX+dirX[i]] = 1;
wallX[y][nextX+dirX[i]][nextX] = 1;
}
// 上|下 移动墙壁
if( dirY[i] != 0 && wallY[x][y][nextY])
{
wallMoved = 1;
wallY[x][y][nextY] = 0;
wallY[x][nextY][y] = 0;
wallY[x][nextY][nextY+dirY[i]] = 1;
wallY[x][nextY+dirY[i]][nextY] = 1;
}
//保存 移动后的坐标
ansX[step]=nextX;
ansY[step]=nextY;
// find solution
if ( nextX==0 || nextX==7 || nextY==0 || nextY==5 )
return 1;
// 继续递归求解
if ( find(step+1) )
return 1;
// 恢复墙壁
if( wallMoved ==1 )
{
if ( dirX[i] != 0 )
{
wallX[y][x][nextX] = 1;
wallX[y][nextX][x] = 1;
wallX[y][nextX][nextX+dirX[i]] = 0;
wallX[y][nextX+dirX[i]][nextX] = 0;
}
if(dirY[i] != 0 )
{
wallY[x][y][nextY] = 1;
wallY[x][nextY][y] = 1;
wallY[x][nextY][nextY+dirY[i]] = 0;
wallY[x][nextY+dirY[i]][nextY] = 0;
}
}
}
return 0;
}
int alg10384()
{
char flag[8];
int i, j, a, b, c;
while(scanf("%s %d %d %d", flag, &a, &b, &c )==4)
{
if (a==0&&b==0&&c==0) break;
if(flag[0]=='x'||flag[0]=='X')
{
wallX[a][b][c]=1;
wallX[a][c][b]=1;
}
if(flag[0]=='y'||flag[0]=='Y')
{
wallY[a][b][c]=1;
wallY[a][c][b]=1;
}
}
showWall();
ansX[0]=beginX;
ansY[0]=beginY;
for(curMaxDepth=1; curMaxDepth <= MaxDepth; curMaxDepth++)
{
if( find(1) )
break;
}
for(i=0; i<=curMaxDepth; i++)
{
printf("%d %d\n", ansX[i], ansY[i]);
}
return 0;
}