UVa 10047 The Monocycle (BFS + 状态判重)

题目:矩阵中一共是四种点,起点,终点,路,墙。一个轮子,只能往前走,这个轮子的轮胎被分为5个部分,每个部分是一个颜色,求的是从原点走到终点,并且在终点的时候轮子着地的颜色和在起点的时候的颜色是一致的,最少多少步。

对于搜索,有的是对图搜索(树划归为图),有的是隐式图搜索。图的搜索还是比较好办,主要是对于隐式图的搜索,是比较有难度的。

最近做过的题目中,对于隐式图的搜索大多都是基于状态作为节点的,一般还有用状态压缩来记录状态(即二进制),那么位运算就是比较常用的。

那么结合这道题来说一下状态。

状态我认为就是能够唯一标识这个点的特点的集合。比如这道题,轮子在的位置,方向,和落地颜色,这几个属性决定了它的状态!这几个属性合起来可以为表示这个点。这样使得这个点不要重复遍历!

那么下面分析这道题:

首先,可以肯定的是这是一道BFS求最短路径的题目。但是不同的是,这个最短路径不是从某一个图上的点到图上另一个点的最短路径,而是从其实状态到终止状态的最短路径!

然后,我们来看一下怎么表示这个状态,显而易见的是,一定要有轮子所在的位置,它的方向,和落地的颜色。

接下来,要说一下,一个轮子在一个格子里面,可以做的操作有三个,左转,右转,前进。

最后,用一个四位的数组来记录这个状态是否被遍历过,vis[x][y][5][4],这里面有5个颜色,4个方向。

还值得注意的是,对于每一个方向,它应该有一个对应的走向,北方是向上走,以此类推,这里,我用一个数组来映射的走向,数组下标为方向的标号,{0, 1, 2, 3}一次表示北,西,南,东。

剩下的见具体的代码!

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

const int N = 30;
const int INF = 500000;
int n, m, ans;
int dis[N][N][5][4];
bool vis[N][N][5][4];
int a[4] = { -1, 0, 1, 0 }, b[4] = { 0, -1, 0, 1 };
char g[N][N];
struct Node{
    int x, y, d, c;
}tmp, S, T, u;
void Bfs() {
    memset( vis, 0, sizeof(vis) );
    ans = INF;
    queue <Node> q;
    q.push(S);
    vis[S.x][S.y][S.c][S.d] = true;
    for ( int i = 0; i <= n; ++i ) 
       for ( int j = 0; j <= m; ++j ) 
          for ( int k = 0; k < 5; ++k )
             for ( int g = 0; g < 4; ++g ) dis[i][j][k][g] = INF;
   dis[S.x][S.y][S.c][S.d] = 0;
   while ( !q.empty() ) {
       u = q.front(); q.pop();
       if ( u.x == T.x && u.y == T.y && u.c == T.c ) {
           ans = dis[u.x][u.y][u.c][u.d];
           break;
       }
       int d = u.d, c = u.c, x = u.x, y = u.y, cc = (c+1) % 5;
       if ( g[x+a[d]][y+b[d]] != '#' && !vis[x+a[d]][y+b[d]][cc][d] && dis[x+a[d]][y+b[d]][cc][d] > dis[x][y][c][d] + 1  ) {          //向前走
           dis[x+a[d]][y+b[d]][cc][d] = dis[x][y][c][d] + 1;
           tmp.x = x+a[d], tmp.y = y+b[d], tmp.c = cc, tmp.d = d;
           vis[tmp.x][tmp.y][tmp.c][tmp.d] = 1;
           q.push( tmp );
       }
       int d1 = (d+1)%4, d2 = d - 1;
       if ( d2 < 0 ) d2 = 3;
       if ( !vis[x][y][c][d1] ) {  //向左转
           dis[x][y][c][d1] = dis[x][y][c][d] + 1;
           tmp.x = x, tmp.y = y, tmp.c = c, tmp.d = d1;
           vis[tmp.x][tmp.y][tmp.c][tmp.d] = 1;
           q.push( tmp );
       }
       if ( !vis[x][y][c][d2] ) {  //向右转
           dis[x][y][c][d2] = dis[x][y][c][d] + 1;
           tmp.x = x, tmp.y = y, tmp.c = c, tmp.d = d2;
           vis[tmp.x][tmp.y][tmp.c][tmp.d] = 1;
           q.push( tmp );
       }
   }
}
int main()
{
    int icase = 1;
    while ( scanf("%d%d", &n, &m) != EOF && (m || n) ) {
        getchar();
        if ( icase > 1 ) cout << endl;
        for ( int i = 0; i <= n+1; ++i ) g[i][0] = g[i][m+1] = '#';
        for ( int j = 0; j <= m+1; ++j ) g[0][j] = g[n+1][j] = '#';
        for ( int i = 1; i <= n; ++i, getchar() ) 
            for ( int j = 1; j <= m; ++j ) {
                scanf("%c", &g[i][j]);
                if ( g[i][j] == 'S' ) S.x = i, S.y = j, S.d = 0, S.c = 0;
                else if ( g[i][j] == 'T' ) T.x = i, T.y = j, T.c = 0;
            }
     //for ( int i = 0; i <= n+1; ++i ) printf("%s\n", g[i]);
        Bfs();
        printf("Case #%d\n", icase++);
        if ( ans == INF ) printf("destination not reachable\n");
        else printf("minimum time = %d sec\n", ans);
    }
}


你可能感兴趣的:(UVa 10047 The Monocycle (BFS + 状态判重))