这道题和UVA上面的一道题目很类似,需要钥匙的题目,那道题是开关,也差不多。不同的是,那道题不需要走到需要关灯的房间就能控制,而这个需要走到门的位置。还有就是房间的表示是不一样的,那个是一维的这个是二维。
但是思想都是一样
题目:矩阵,有的地方有钥匙,有的地方有门,有的是墙,有的是起点还有终点,还有路。门必须用相应的钥匙可以打开。出口有多个,这个要注意。
第一次wa就是wa在这里了,因为,在break一次后,外层循环也需要一个break,可以小妞我给忘了!!!
好吧,说一下分析:主要有一点药想明白,标记什么,状态怎么表示!状态这里,无非就是设计了两个东西,一个是位置,另一个是手里的钥匙的情况。可以用一个数组表示手里钥匙的情况,但是为了便于标记,把这个钥匙的情况压缩一下,就妥妥哒了!
数据不大,开始我想用的是map来标记,可惜如果key是结构体的话,那么需要用重载的,我就是傻呀,不会先试一下呀,这下可好,写了一大篇子代码,编译不过,这我就不高兴了,于是果断重写,用三维数组来表示,好在数据不大。下面就来表示一下重载的怎么写,学习的链接:http://bbs.chinaunix.net/thread-1538318-1-1.html
接着来说,千万不要标记已经走过的格子,因为拿完钥匙可以再走,这是允许的
好了,千言万语,尽在代码之中:
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cctype>
#include <map>
using namespace std;
const int N = 101;
const int INF = 100000000;
int n, m, ans, d[N][N];
int sx, sy, ex, ey;
char g[N][N];
bool vis[N][N][20];
vector <pair<int, int> > v;
struct Node{ int x, y, h; }e;
int match( char x ) {
if ( x == 'B' || x == 'b' ) return 0;
if ( x == 'Y' || x == 'y' ) return 1;
if ( x == 'R' || x == 'r' ) return 2;
if ( x == 'G' || x == 'g' ) return 3;
}
bool BFS() {
bool find = false;
queue< Node > Q;
e.x = sx, e.y = sy, e.h = 0;
Q.push(e);
memset(vis, 0, sizeof(vis) );
vis[sx][sy][0] = true;
int x[4] = { 0, 0, 1, -1 }, y[4] = { 1, -1, 0, 0 };
memset( d, 0, sizeof(d) );
//for ( int i = 0; i < v.size(); ++i ) d[v[i].first][v[i].second] = INF;
while ( !Q.empty() ) {
Node u = Q.front(); Q.pop();
//printf("%d %d %d %d\n", u.x, u.y, u.h, d[u.x][u.y]);
for ( int i = 0, xx, yy, move; i < 4; ++i ) {
xx = u.x + x[i], yy = u.y + y[i], move = match( g[xx][yy] ), e.x = xx, e.y = yy, e.h = u.h;
if ( g[xx][yy] == '#' ) continue;
if ( g[xx][yy] == '.' || g[xx][yy] == '*' ) {
if ( !vis[e.x][e.y][e.h] ) {
vis[e.x][e.y][e.h] = true;
Q.push(e);
d[xx][yy] = d[u.x][u.y] + 1;
}
}
else if ( g[xx][yy] == 'X' ) {
find = true;
ex = xx, ey = yy;
d[ex][ey] = d[u.x][u.y] + 1;
//printf("--%d %d\n", ex, ey);
break;
}
else if ( islower(g[xx][yy]) ) {
e.h = (u.h | ( 1 << move ));
//printf("%d %d %d %d\n",e.x, e.y, e.h, d[e.x][e.y]);
if ( !vis[e.x][e.y][e.h] ) {
vis[e.x][e.y][e.h] = true;
Q.push(e);
d[xx][yy] = d[u.x][u.y] + 1;
}
}
else if ( isupper(g[xx][yy]) ) {
if ( (u.h & ( 1 << move ) )== 0 ) continue;
e.h = u.h;
if ( !vis[e.x][e.y][e.h] ) {
vis[e.x][e.y][e.h] = true;
Q.push(e);
d[xx][yy] = d[u.x][u.y] + 1;
}
}
}
if ( find ) break;
}
return find;
}
int main()
{
while ( scanf("%d%d", &n, &m) != EOF && ( n || m ) ) {
getchar();
ans = INF;
memset( g, '\0', sizeof(g) );
for ( int i = 0; i <= n+1; ++i ) g[i][0] = g[i][m+1] = '#';
for ( int i = 0; i <= m+1; ++i ) g[0][i] = g[n+1][i] = '#';
for ( int i = 1; i <= n; ++i, getchar() )
for ( int j = 1; j <= m; ++j ) {
scanf("%c", &g[i][j]);
if ( g[i][j] == '*' ) sx = i, sy = j;
/*else if ( g[i][j] == 'X' ) {
pair<int, int> p;
p.first = i, p.second = j;
v.push_back( p );
}*/
}
//for ( int i = 0; i <= n+1; ++i ) printf("%s\n", g[i]);
if ( BFS() ) printf("Escape possible in %d steps.\n", d[ex][ey]);
else printf("The poor student is trapped!\n");
}
}
这篇博客介绍了如何使用状态压缩和BFS解决一个包含钥匙和门的矩阵迷宫问题。作者强调理解何时标记状态以及如何表示手中钥匙的情况,通过一个压缩数组来简化表示。在解决过程中,作者遇到并解决了因忘记在外层循环中加入break而导致的错误。虽然数据规模不大,但作者最初尝试使用map进行标记,发现结构体作为key需要重载操作符,因此改用三维数组实现。博客提醒读者,拿完钥匙后可以重新走过已访问的格子,这是允许的策略。
635

被折叠的 条评论
为什么被折叠?



