迷宫问题c程序

迷 宫问题

自己写的迷宫程序,新手,有很多不足之处,希望通过这种方式多多学习提高

问题描述

迷宫游戏有多种。有的迷宫只要你能走出来就算成功;有的是要求不但能走出来,而且走的步数越少得分越高。为了能得到高分,你肯定在路线的选择上下功夫,尽量用最少的步数走出迷宫。
现有一个迷宫,可以用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;
}

本人新手,能力有限,有问题的地方还请多多指教。有好的思路建议还望不吝赐教!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值