迷 宫问题
自己写的迷宫程序,新手,有很多不足之处,希望通过这种方式多多学习提高
问题描述
迷宫游戏有多种。有的迷宫只要你能走出来就算成功;有的是要求不但能走出来,而且走的步数越少得分越高。为了能得到高分,你肯定在路线的选择上下功夫,尽量用最少的步数走出迷宫。
现有一个迷宫,可以用M行N列的矩阵来描述,迷宫中有以下6种标志:
(1)$ :代表你所在的初始位置;
(2)& :迷宫的出口位置;
(3)# :墙,无法通过;
(4). :地面,可以通过;
(5)A、B、C、…、Z :每个大写字母代表一个门,可以用对应的小写字母的钥匙打开。
(6)a、b、c、…、z :每个小写字母代表一把钥匙,可以打开相应大写字母对应的门。
迷宫说明:
(1)迷宫的四周都有墙,所以你无法走出这片M*N的区域,只能从出口’&’处离开迷宫;
(2)在迷宫中你只能向东西南北四个方向走(当然有墙的地方你无法达到;如果没有相应的钥匙,有门的地方你也无法到达)。
(3)如果能走到有小写字母(钥匙)的位置,你就可以拿到它,并用来打开相应大写字母的门,钥匙a只能开A门,钥匙b只能开B门,……
如下列迷宫
最快走出迷宫的方法是:从初始位置$走12步到达钥匙a处拿到钥匙后,然后再走5步到达A处,打开门A后再走1步到达出口&,共走了12+5+1=18步。上述迷宫中,如果你拿不到钥匙a,就无法打开门A,也就到不了出口。有的迷宫可能不需要走有门的地方,就能最快走到迷宫出口。你的任务是,计算出走出迷宫需要的最少步数是多少?
数据输入格式
5 5
1
&A..$
#.##.
...#.
.#.#.
a#...
数据规模和约定
存在10%的数据,P=0;
存在20%的数据,P<=1;
存在40%的数据,P<=2;
对于30%的数据,M,N<=15;
对于100%的数据,1<=M,N<=50,0<=P<=10。
保证迷宫中’$’、’&’只出现一次;同一个大小写字母只出现一次(p=0的迷宫里面没有钥匙和门)。
下面是我写的程序
大体思路是利用深度优先搜索算法,搜索出口。遇到钥匙,就拿钥匙,从钥匙开始重新搜索出口。
#include <stdio.h>
char maze[50][50];
int fx[] = { 1, -1, 0, 0 };
int fy[] = { 0, 0, -1, 1 };
int p; /*门的数量 */
int xzb[20] = { 0 };
int yzb[20] = { 0 };
int len; /*有效搜索路径的长度 */
int key[10] = { 0 }; /*存储已获得的钥匙 */
int IsGetkey(char n);
int IsKey(char n);
int check(char maze[50][50], int n, int m, int i, int j);
int search(char maze[50][50], char exit,int n, int m, int i, int j, int pi,
int pj);
int
main(void)
{
int i, j;
int n, m;
int ei, ej; /*搜索入口 */
if (freopen("maze.in", "r", stdin) == NULL)
return -1;
scanf("%d%d", &n, &m);
scanf("%d", &p);
for (i = 0; i < n; i++)
for (j = 0; j < m; j++) {
scanf("%c", &maze[i][j]);
if (maze[i][j] == '\n')
scanf("%c", &maze[i][j]);
}
for (i = 0; i < n + 1; i++) {
for (j = 0; j < m; j++) {
printf("%c", maze[i][j]);
}
printf("\n");
}
close(stdin);
for (i = 0; i < n + 1; i++)
for (j = 0; j < m; j++)
if (maze[i][j] == '$') {
ei = i;
ej = j;
i = 100;
j = 100;
}
search(maze, '&', n, m, ei, ej, -1, -1);
}
/*搜索*/
int
search(char maze[50][50], char exit,int n, int m, int i, int j, int pi, int pj)
{
char tmp;
int k, ni, nj; /*ni,nj表示下一个搜索点的坐标 */
if (maze[i][j] == exit) {
printf("到迷宫出口需要%d步\n",len);
printf("出口坐标:<%d,%d>\n\n", i, j);
for (k = 0; k < len; k++)
printf("<%d,%d>\n", xzb[k], yzb[k]);
return 1;
} else if (IsKey(maze[i][j])) {
tmp = maze[i][j];
maze[i][j] = '.';
search(maze, '&',n, m, i, j, -1, -1);
}
for (k = 0; k < 4; k++) {
ni = i + fx[k];
nj = j + fy[k];
if (ni == pi && nj == pj)
continue;
if (check(maze, n, m, ni, nj)) {
xzb[len] = i;
yzb[len] = j;
len += 1;
if (search(maze, '&',n, m, ni, nj, i, j) == 1)
return 1;
}
}
len -= 1;
return -1;}
/*检查下一个搜索点是否有效*/
int
check(char maze[50][50], int n, int m, int i, int j)
{
int flag = 1;
if (i < 0 || i >= n || j < 0 || j >= m)
flag = 0;
else if (maze[i][j] >= 'A' && maze[i][j] <= 'Z'
&& IsGetkey(maze[i][j])) ;
else if (maze[i][j] != '.' && maze[i][j] != '&' && maze[i][j] < 'a')
flag = 0;
return flag;
}
/*IsKey 判断当前搜索点是不是钥匙,是返回1
* 否返回 0
* */
int
IsKey(char n)
{
if (n >= 'a' && n <= 'a' + p - 1) {
key[n - 'a'] += 1;
return 1;
} else
return 0;
}
/*如果当前搜索点是门,判断当前有没有该门钥匙
* */
int
IsGetkey(char n)
{
if (key[n - 65] == 1 || n >= 'a') {
key[n - 65] -= 1; /*每个钥匙只有一次使用机会 */
return 1;
}
return 0;
}