Mapping the Route

Description

Finding a path through a maze is a popular problem for computers. In this problem, a maze will consist of a rectangular array of square cells, each of which may have walls on the north, south, east and/or west sides of the cell. One cell will be identified as the starting point, and another will be identified as the goal. Your task is to find the unique route from the starting point to the goal, label each cell in the path with its sequence in the path, identify the cells that were visited but that were not in the path, and display the maze.

The algorithm you use to find a path through the maze must be the one described below. Imagine a robot is positioned in the starting cell. The robot first attempts to go west from that cell, then north, then east, then south, in sequence. The robot can move in the selected direction if

(a) there is no wall preventing it from moving in that direction, and
(b) it has not yet been in the next cell in that direction.

When the robot reaches the goal, its trip is over. If the robot reaches a cell at which no further progress is possible, it retreats to the previous cell it occupied and attempts to move in the next untried direction.

Consider the simple maze shown on the left below. It is two cells high and three cells wide. The starting cell is labeled `S' and the goal cell is labeled `G'. When the robot starts, it would first try to move west (left), but finds a wall. It then tries to move north (up), and is again blocked by a wall. A wall also prevents it from moving east (right), so it finally tries to move south (down), and succeeds. From the new cell it will eventually move east. Here it repeats its movement algorithm. Although no wall blocks its potential westward movement, it has already 'visited' the cell in that direction, so it next tries to move north, and is successful. Unfortunately, after moving north, it finds no way to extend its path, and so it retreats to the previously occupied cell. Now it tries to move east, and is successful. From that cell it will move north, and there it finds the goal. The maze that would be displayed on the output is shown on the right below. Note that the starting cell is labeled `1', each cell in the path to the goal (including the one containing the goal) is labeled with its sequence number, and each cell that was visited but is not in the path is labeled with question marks.

                     +---+---+---+        +---+---+---+
                     | S |   | G |        |  1|???|  5|
                     +   +   +   +        +   +   +   +
                     |           |        |  2   3   4|
                     +---+---+---+        +---+---+---+
  


Input

View the maze as an array of cells, with the northernmost row being row 1, and the westernmost column being column 1. In the maze above, the starting cell is row 1, column 1, and the goal cell is row 1, column 3.

There will be one or more mazes to process in the input. For each maze there will first appear six integers. The first two give the height (number of rows) and width (numer of columns) of the maze (in cells). The next two give the position (row and column number) of the starting cell, and the last two give the position of the goal. No maze will have more than 12 rows or 12 columns, and there will always be a path from the starting point to the goal.

Following the first six integers there will appear one integer for each cell, in row major order. The value of each integer indicates whether a cell has a wall on its eastern side (1) and whether it has a wall on its southern side (2). For example, a cell with no eastern or southern wall has a value of 0. A cell with only a southern wall has a value of 2. A cell with both an eastern and a southern wall has a value of 3. The cells on the periphery of the maze always have appropriate walls to prevent the robot from leaving the maze; these are not specified in the input data.

The last maze in the input data will be followed by six zeroes.


Output

For each maze, display the maze as shown in the example above and the expected output below, appropriately labeled and prefixed by the maze number. The mazes are numbered sequentially starting with 1. Print two blank lines after each case.


Sample Input

2 3 1 1 1 3
1 1 0
0 0 0

4 3 3 2 4 3
0 3 0
0 2 0
0 3 0
0 1 0

0 0 0 0 0 0


Sample Output

Maze 1

+---+---+---+
|  1|???|  5|
+   +   +   +
|  2   3   4|
+---+---+---+


Maze 2

+---+---+---+
|??? ???|???|
+   +---+   +
|  3   4   5|
+   +---+   +
|  2   1|  6|
+   +---+   +
|       |  7|
+---+---+---+



这道题首先需要注意最后也有两个空行,只不过需要保存能走的方向,在这道题中学到了一个用栈实现搜索dfs的方法,
还要注意方向是有优先级,
           1
       0       2
           3
能走到某个方向时就一直往下走,和dfs的思想是一样,会附加另一个dfs的代码。
#include <stdio.h>
const int maxn = 25;
int n, m, begin_x, begin_y, end_x, end_y;
/*
    1
  0   2
    3
*/  //题目已给出方向的优先级
int dx[4] = { 0, -1, 0, 1 }, dy[4] = { -1, 0, 1, 0 };
struct node
{
    int d[4];
    int seq, vis, v;
} a[maxn][maxn];
int stack[maxn*maxn][2];
int init ( )
{
    scanf ( "%d%d%d%d%d%d", &n, &m, &begin_x, &begin_y, &end_x, &end_y );
    if ( n+m+begin_x+begin_y+end_x+end_y == 0 ) //全为0时退出
        return 0;
    for ( int i = 0; i < n; i ++ )
    {
        for ( int j = 0; j < m; j ++ )
        {
            scanf ( "%d", &a[i][j].v );
            a[i][j].seq = a[i][j].vis = 0;
            switch ( a[i][j].v )    //将能走的方向标记
            {
                case 0 :
                    a[i][j].d[2] = 0;
                    a[i][j].d[3] = 0;
                    a[i][j+1].d[0] = 0;
                    a[i+1][j].d[1] = 0;
                break ;
                case 1 :
                    a[i][j].d[2] = 1;
                    a[i][j].d[3] = 0;
                    a[i][j+1].d[0] = 1;
                    a[i+1][j].d[1] = 0;
                break ;
                case 2 :
                    a[i][j].d[2] = 0;
                    a[i][j].d[3] = 1;
                    a[i][j+1].d[0] = 0;
                    a[i+1][j].d[1] = 1;
                break ;
                case 3 :
                    a[i][j].d[2] = 1;
                    a[i][j].d[3] = 1;
                    a[i][j+1].d[0] = 1;
                    a[i+1][j].d[1] = 1;
                break ;
            }
            if ( i == 0 )   //边界全是不能通过
                a[i][j].d[1] = 1;
            if ( j == 0 )
                a[i][j].d[0] = 1;
            if ( i == n-1 )
                a[i][j].d[3] = 1;
            if ( j == m-1 )
                a[i][j].d[2] = 1;
        }
    }
    return 1;
}
void bfs ( )
{
    int nx, ny;
    stack[0][0] = begin_x-1;
    stack[0][1] = begin_y-1;    //注意我写的下标是从0开始的
    a[begin_x-1][begin_y-1].vis = 1;
    for ( int top = 0; top < n*m && top >= 0; ) //最多n*m次,还不能越界
    {
        int ok = 0;
        //printf ( "%d\n", top );
        for ( int i = 0; i < 4; i ++ )
        {
            int x = stack[top][0];
            int y = stack[top][1];
            if ( a[x][y].d[i] == 0 )    //查看此点i方向是否可走
            {
                nx = x+dx[i];
                ny = y+dy[i];
                if ( a[nx][ny].vis )    //此点走过
                    continue ;
                a[nx][ny].vis = 1;
                ok = 1;
                top ++;
                stack[top][0] = nx; //加入栈
                stack[top][1] = ny;
            }
            if ( nx == end_x-1 && ny == end_y-1 )   //终点也要减1
            {
                for ( int j = 0; j <= top; j ++ )
                //此栈中的坐标就是从起点到终点的路线,并保存序列值
                    a[ stack[j][0] ][ stack[j][1] ].seq = j+1;
                return ;
            }
            if ( ok )
            //写过一个方向就直接退出,这样就只往一个方向走,相当于dfs
                break ;
        }
        if ( ok == 0 )
            top --;
    }
}
void print ( )  //打印
{
    printf ( "+" );
    for ( int i = 0; i < m; i ++ )
        printf ( "---+" );
    printf ( "\n" );
    for ( int i = 0; i < n; i ++ )
    {
        printf ( "|" );
        for ( int j = 0; j < m; j ++ )
        {
            if ( a[i][j].vis && a[i][j].seq )
                printf ( "%3d", a[i][j].seq );
            else if ( a[i][j].vis && a[i][j].seq == 0 )
                printf ( "???" );
            else if ( a[i][j].vis == 0 && a[i][j].seq == 0 )
                printf ( "   " );
            if ( a[i][j].d[2] )
                printf ( "|" );
            else
                printf ( " " );
        }
        printf ( "\n" );
        printf ( "+" );
        for ( int j = 0; j < m; j ++ )
        {
            if ( a[i][j].d[3] )
                printf ( "---+" );
            else
                printf ( "   +" );
        }
        printf ( "\n" );
    }
}
int main ( )
{
    int cas = 1;
    //freopen ( "in0.in", "r", stdin );
    while ( init ( ) )
    {
        bfs ( );
        printf ( "Maze %d\n\n", cas ++ );
        print ( );
        printf ( "\n\n" );  //每组数据后面两个换行
    }
    return 0;
}

dfs代码(但是发现用非递归的时间不比递归代码复杂度低)

#include <stdio.h>
#include <string.h>
#define BUG printf ( "Here!\n" )
const int maxn = 25;
int n, m, begin_x, begin_y, end_x, end_y, flag;
/*
    1
  0   2
    3
*/
int dx[4] = { 0, -1, 0, 1 }, dy[4] = { -1, 0, 1, 0 };
struct node
{
    int d[4];
    int v;
} a[maxn][maxn];
int vis[maxn][maxn], seq[maxn][maxn];
int init ( )    //初始化可走方向
{
    scanf ( "%d%d%d%d%d%d", &n, &m, &begin_x, &begin_y, &end_x, &end_y );
    if ( n+m+begin_x+begin_y+end_x+end_y == 0 )
        return 0;
    for ( int i = 0; i < n; i ++ )
    {
        for ( int j = 0; j < m; j ++ )
        {
            scanf ( "%d", &a[i][j].v );
            switch ( a[i][j].v )
            {
                case 0 :
                    a[i][j].d[2] = 0;
                    a[i][j].d[3] = 0;
                    a[i][j+1].d[0] = 0;
                    a[i+1][j].d[1] = 0;
                break ;
                case 1 :
                    a[i][j].d[2] = 1;
                    a[i][j].d[3] = 0;
                    a[i][j+1].d[0] = 1;
                    a[i+1][j].d[1] = 0;
                break ;
                case 2 :
                    a[i][j].d[2] = 0;
                    a[i][j].d[3] = 1;
                    a[i][j+1].d[0] = 0;
                    a[i+1][j].d[1] = 1;
                break ;
                case 3 :
                    a[i][j].d[2] = 1;
                    a[i][j].d[3] = 1;
                    a[i][j+1].d[0] = 1;
                    a[i+1][j].d[1] = 1;
                break ;
            }
            if ( i == 0 )
                a[i][j].d[1] = 1;
            if ( j == 0 )
                a[i][j].d[0] = 1;
            if ( i == n-1 )
                a[i][j].d[3] = 1;
            if ( j == m-1 )
                a[i][j].d[2] = 1;
        }
    }
    return 1;
}
void print ( )  //打印
{
    printf ( "+" );
    for ( int i = 0; i < m; i ++ )
        printf ( "---+" );
    printf ( "\n" );
    for ( int i = 0; i < n; i ++ )
    {
        printf ( "|" );
        for ( int j = 0; j < m; j ++ )
        {
            if ( vis[i][j] && seq[i][j] )   //对走过或者是关键路线进行对应输出
                printf ( "%3d", seq[i][j] );
            else if ( vis[i][j] && seq[i][j] == 0 )
                printf ( "???" );
            else if ( vis[i][j] == 0 && seq[i][j] == 0 )
                printf ( "   " );
            if ( a[i][j].d[2] )
                printf ( "|" );
            else
                printf ( " " );
        }
        printf ( "\n" );
        printf ( "+" );
        for ( int j = 0; j < m; j ++ )
        {
            if ( a[i][j].d[3] )
                printf ( "---+" );
            else
                printf ( "   +" );
        }
        printf ( "\n" );
    }
    printf ( "\n\n" );  //最后两个换行
}
void dfs ( int x, int y, int step )
{
    if ( flag )
        return ;
    if ( vis[x][y] )
        return ;
    vis[x][y] = 1;  //标记为走过
    seq[x][y] = step;   //统计第几步走到x y
    if ( x == end_x-1 && y == end_y-1 )
    {
        //BUG;
        print ( );  //路线成立就直接打印
        flag = 1;
        return ;
    }
    for ( int i = 0; i < 4; i ++ )
        if ( a[x][y].d[i] == 0 )
            dfs ( x+dx[i], y+dy[i], step+1 );
    seq[x][y] = 0;  //如果没有走通将值设回来
}
int main ( )
{
    int cas = 1;
    //freopen ( "in0.in", "r", stdin );
    while ( init ( ) )
    {
        flag = 0;
        memset ( vis, 0, sizeof ( vis ) );
        memset ( seq, 0, sizeof ( seq ) );
        printf ( "Maze %d\n\n", cas ++ );
        dfs ( begin_x-1, begin_y-1, 1 );
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值