【BFS】HDU1885 - Key Task

题意

给一个图,问最少需要多少步可以逃出去。

*:起点

#:墙,不走能

.:路

X:出口

b,y,r,g:对应每个大写字母的钥匙

B,Y,R,G:对应颜色的门,需要有对应颜色的钥匙才能打开

每个钥匙可以打开多扇同颜色的门,可能有多个出口。

思路

求最短路,用BFS。因为为了拿钥匙,会重复走某一个地方,所以不能用二维数组vis记录走没走过;用三维数组记录在某个点时是否有某种颜色的钥匙。

在记录走到某点是否有某钥匙的时候遇到了困难,死活做不出来,看了题解之后是使用了状态压缩:用k = 0,1,2,3分别表示b,y,r,g这四种颜色的钥匙,1<<k表示颜色为k的钥匙,用此点的所拥有的钥匙颜色key与1<<k按位与进行比较,如果等于0,就是没有这种颜色的钥匙。

(按位与:参与运算的两数各对应的二进位相与。只要对应的二个二进位都为1时,结果位就为1。eg: key = 1100,对应的十进制为12,即拥有2, 3两种颜色的钥匙,若与1<<2比较,即十进制下12 & 4,结果不为0,即此点有这种颜色的钥匙)

总结

1. 初步了解了状压,终于明白了按位与的作用,开心啊,不错不错,233

2. 比原来更了解了一些bfs,将在某点可走的方向都存入队列中,下一次又是另一个点可走的方向存入进去,如果某个方向走不通,就都弹出了队列。刚开始觉得有好几个出口应该找好几次,然后输出最小的那个,现在知道了只要通过一次bfs就能找到最短的那条路,而不是多次

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <string>
  6 #include <queue>
  7 #include <cctype>
  8 using namespace std;
  9 const int maxn = 105;
 10 int n, m;
 11 char G[maxn][maxn];
 12 int vis[maxn][maxn][35];
 13 const int dr[] = {-1, 0, 1, 0};
 14 const int dc[] = { 0, 1, 0,-1};
 15 
 16 struct Node
 17 {
 18     int r, c, key, step;
 19     Node(int r = 0, int c = 0, int key = 0, int step = 0):r(r), c(c), key(key), step(step){}
 20 };
 21 
 22 int getColor(char key)
 23 {
 24     key = tolower(key);
 25     if(key == 'b') return 0;
 26     else if(key == 'y') return 1;
 27     else if(key == 'r') return 2;
 28     else if(key == 'g') return 3;
 29 }
 30 
 31 bool isInside(int r, int c)
 32 {
 33     if(r > 0 && r <= n && c > 0 && c <= m && G[r][c] != '#')
 34         return true;
 35     else
 36         return false;
 37 }
 38 
 39 void bfs(int rr, int cc)
 40 {
 41     queue<Node> q;
 42     memset(vis, 0, sizeof vis);
 43     Node node(rr, cc, 0, 0);
 44     q.push(node);
 45     while(!q.empty()) {
 46         Node u = q.front();
 47         q.pop();
 48         if(G[u.r][u.c] == 'X') {
 49             printf("Escape possible in %d steps.\n", u.step);
 50             return;
 51         }
 52         for(int i = 0; i < 4; i++) {
 53             Node v(u.r + dr[i], u.c + dc[i], u.key, u.step+1);
 54             if(isInside(v.r, v.c)) {
 55                 if(islower(G[v.r][v.c])) {
 56                     int k = getColor(G[v.r][v.c]);
 57                     if((v.key & (1 << k)) == 0) { //如果没有这种颜色的钥匙
 58                         v.key += (1 << k); //把这种颜色的钥匙加入进去
 59                     }
 60                     if(!vis[v.r][v.c][v.key]) {
 61                         vis[v.r][v.c][v.key] = 1;
 62                         q.push(v);
 63                     }
 64                 }
 65                 else if(isupper(G[v.r][v.c]) && G[v.r][v.c] != 'X') {
 66                     int k = getColor(G[v.r][v.c]);
 67                     if(v.key & (1 << k) && !vis[v.r][v.c][v.key]) {
 68                         vis[v.r][v.c][v.key] = 1;
 69                         q.push(v);
 70                     }
 71                 }
 72                 else {
 73                     if(!vis[v.r][v.c][v.key]) {
 74                         vis[v.r][v.c][v.key] = 1;
 75                         q.push(v);
 76                     }
 77                 }
 78             }
 79         }
 80     }
 81     printf("The poor student is trapped!\n");
 82 }
 83 int main()
 84 {
 85     freopen("in.txt", "r", stdin);
 86     while(scanf("%d %d", &n, &m) && n) {
 87         memset(G, '#', sizeof G);
 88         int x, y;
 89         for(int i = 1; i <= n; i++) {
 90             scanf("%s", G[i]+1);
 91             G[i][m+1] = '#';
 92             G[i][m+2] = '\0';
 93             if(strchr(G[i], '*')) {
 94                 x = i;
 95                 y = strchr(G[i], '*') - *G - i*105;
 96             }
 97         }
 98         //printf("%d %d\n", x, y);
 99         bfs(x, y);
100     }
101     return 0;
102 }

 

posted @ 2016-11-18 16:05  kikii233  阅读(107)  评论(0编辑  收藏  举报