uva10384 The Wall Pusher 推门游戏

来源:互联网 发布:科比布莱恩特生涯数据 编辑:程序博客网 时间:2024/05/29 14:27

问题

从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 7x 2 0 1x 2 2 3x 2 4 5x 2 6 7x 3 0 1x 3 1 2x 3 2 3x 3 4 5x 3 5 6x 3 6 7x 4 1 2x 4 3 4x 4 5 6y 1 0 1y 1 1 2y 1 3 4y 1 4 5y 2 0 1y 2 2 3y 2 3 4y 2 4 5y 3 0 1y 3 1 2y 3 2 3y 3 4 5y 4 0 1y 4 1 2y 4 2 3y 4 4 5y 5 0 1y 5 2 3y 5 3 4y 5 4 5y 6 0 1y 6 3 4y 6 4 50 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;}
原创粉丝点击