题目大意:孙悟空去救唐僧,要集齐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; }