题目大意:孙悟空去救唐僧,要集齐m把钥匙才能救他,要得到第二把钥匙就必须先拿到第一把,以此类推。路上还有至多五条蛇,必须杀死蛇才能继续前进,每次杀死一条蛇,消耗一个单位的时间。另外,每前行一格,也要耗费一个单位时间。求最短时间。
分析:带限制的BFS。一般做这种题,就是增加vis数组的维数,使其能够正确表示当前的状态。这里需要记录的有是两个坐标,还有当前钥匙的情况,和杀死哪些蛇的情况。所以,一共需要四维。由于钥匙的顺序是固定的,因此,开10就够了。而杀死蛇的顺序不是固定的,并且,蛇至多只有5条,所以,给蛇编号后,用二进制来记录。
代码:
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
struct Node {
int x, y;
int t;
int key;
int snake;
Node() {}
Node(int x, int y, int t, int key, int snake):x(x), y(y), t(t), key(key), snake(snake) {}
};
int dx[4] = {0, 1, 0, -1};
int dy[4] = {-1, 0, 1, 0};
char g[111][111];
int vis[111][111][10][1<<6];
int n, m;
int sn;
int ex, ey;
int ans;
bool ok(Node p) {
if(p.x == ex && p.y == ey && p.key == m) {
ans = p.t;
return true;
}
else return false;
}
void bfs(int x, int y) {
queue<Node> q;
q.push(Node(x, y, 0, 0, 0));
while(!q.empty()) {
Node p = q.front();
q.pop();
if(ok(p)) return;
if(vis[p.x][p.y][p.key][p.snake]) continue;
vis[p.x][p.y][p.key][p.snake] = 1;
for(int i = 0; i < 4; i++) {
int tx = p.x+dx[i];
int ty = p.y+dy[i];
if(g[tx][ty] != '#') {
if(g[tx][ty] >= 'A' && g[tx][ty] < 'F') {
int c = g[tx][ty]-'A';
if(p.snake>>c & 1) { //判断之前有没有杀死过这条蛇
q.push(Node(tx, ty, p.t+1, p.key, p.snake));
}
else {
q.push(Node(tx, ty, p.t+2, p.key, p.snake|1<<c));
}
}
else if(isdigit(g[tx][ty])) {
int k = g[tx][ty]-'0';
if(p.key+1 == k) { //判断有没有拿到前一把钥匙
q.push(Node(tx, ty, p.t+1, k, p.snake));
}
else {
q.push(Node(tx, ty, p.t+1, p.key, p.snake));
}
}
else {
q.push(Node(tx, ty, p.t+1, p.key, p.snake));
}
}
}
}
}
int main() {
while(scanf("%d%d", &n, &m) && n) {
memset(g, '#', sizeof(g));
memset(vis, 0, sizeof(vis));
int sx, sy;
sn = 0;
for(int i = 1; i <= n; i++) {
getchar();
for(int j = 1; j <= n; j++) {
scanf("%c", &g[i][j]);
if(g[i][j] == 'K')
sx = i, sy = j;
else if(g[i][j] == 'T')
ex = i, ey = j;
else if(g[i][j] == 'S') {
g[i][j] = 'A'+sn; //给蛇编号
sn++;
}
}
}
ans = -1;
bfs(sx, sy);
if(ans != -1) printf("%d\n", ans);
else printf("impossible\n");
}
return 0;
}