台州 OJ 2850 Key Task BFS

描述

 

The Czech Technical University is rather old - you already know that it celebrates 300 years of its existence in 2007. Some of the university buildings are old as well. And the navigation in old buildings can sometimes be a little bit tricky, because of strange long corridors that fork and join at absolutely unexpected places.

The result is that some first-graders have often difficulties finding the right way to their classes. Therefore, the Student Union has developed a computer game to help the students to practice their orientation skills. The goal of the game is to find the way out of a labyrinth. Your task is to write a verification software that solves this game.

The labyrinth is a 2-dimensional grid of squares, each square is either free or filled with a wall. Some of the free squares may contain doors or keys. There are four different types of keys and doors: blue, yellow, red, and green. Each key can open only doors of the same color.

You can move between adjacent free squares vertically or horizontally, diagonal movement is not allowed. You may not go across walls and you cannot leave the labyrinth area. If a square contains a door, you may go there only if you have stepped on a square with an appropriate key before.

输入

 

The input consists of several maps. Each map begins with a line containing two integer numbers R and C (1 <= R,C <= 100) specifying the map size. Then there are R lines each containing C characters. Each character is one of the following:

Character Meaning
Hash mark # Wall
Dot . Free square
Asterisk * Your position
Uppercase letter B Y R G Blue, yellow, red, or green door
Lowercase letter b y r g Blue, yellow, red, or green key
Uppercase X X Exit

Note that it is allowed to have

  • more than one exit,
  • no exit at all,
  • more doors and/or keys of the same color, and
  • keys without corresponding doors and vice versa.

You may assume that the marker of your position ("*") will appear exactly once in every map.

There is one blank line after each map. The input is terminated by two zeros in place of the map size.

输出

 

For each map, print one line containing the sentence "Escape possible in S steps.", where S is the smallest possible number of step to reach any of the exits. If no exit can be reached, output the string "The poor student is trapped!" instead.

One step is defined as a movement between two adjacent cells. Grabbing a key or unlocking a door does not count as a step.

地图中存在一些障碍物、钥匙、门。 只有拥有与门颜色相同的钥匙时,才能打开门。 这里没看懂题目意思,搞了好久,以为开一个门就会少一把钥匙,但一把钥匙其实可以开无数个门,只要颜色相同。

广搜的时候,最重要的是把每个节点的内容搞懂,对于这题来说,(x, y) 坐标是一个维度,拥有不同的钥匙又是一个维度,因此 (x, y, 拥有的钥匙) 才是一个完整的状态。

代码:

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

const int MAX = 105;

struct Node{
    int x, y, state, step;    //坐标,有哪些钥匙,以及步数
    Node(){}
    Node(int nx, int ny, int nstate, int nstep) : x(nx), y(ny), state(nstate), step(nstep){} 
}; 

int vis[MAX][MAX][1<<5];        //在(x,y)坐标下有哪些钥匙 为一个状态
char G[MAX][MAX];
int n, m;
int r1, c1;        //起点坐标
char keys[5] = "byrg";        //钥匙 
char doors[5] = "BYRG";         //
int dx[4] = {-1, 0, 1, 0};
int dy[4] = { 0, 1, 0,-1};

int bfs();        //返回到 'X' 的最少步数 
bool canOpen(int state, char door);        //能否打开门,state为当前拥有的钥匙,door 为门 

int main(){
//    freopen("input.txt", "r", stdin);
    
    while(cin >> n >> m && n+m != 0){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                cin >> G[i][j];
                if(G[i][j] == '*'){
                    r1 = i;  c1 = j;
                }
            }
        }
        
        //BFS
        int ans = bfs();
        
        if(ans == -1){
            cout << "The poor student is trapped!" << endl;
        }else{
            cout << "Escape possible in " << ans << " steps." << endl;
        }
    }
    
    return 0;
} 
 
int bfs(){
    memset(vis, 0, sizeof(vis));
    queue<Node> que;
    que.push(Node(r1, c1, 0, 0));
    vis[r1][c1][0] = 1;
    while(!que.empty()){
        Node p = que.front();  que.pop();
        if(G[p.x][p.y] == 'X')        //到终点了 
            return p.step;
        for(int i=0; i<4; i++){
            int x = p.x + dx[i];
            int y = p.y + dy[i];
            int state = p.state;
            if(x < 1 || x > n || y < 1 || y > m || G[x][y] == '#' || vis[x][y][state] == 1)    //出界或者改状态访问过了
                continue;
            if(G[x][y] > 'A' && G[x][y] < 'Z' && G[x][y] != 'X' && !canOpen(state, G[x][y])){        //是门并且不能开门
                continue;
            }
            if(G[x][y] > 'a' && G[x][y] < 'z'){            //有钥匙
                int k;
                for(k=0; k<4; k++)
                    if(keys[k] == G[x][y])
                        break;
                state = (state | (1<<(3-k)));
            }
            que.push(Node(x, y, state, p.step+1));
            vis[x][y][state] = 1; 
        }
    }
    
    return -1;
}

bool canOpen(int state, char door){
    int i;
    for(i=0; i<4; i++){            //该门对应的下标 
        if(doors[i] == door)
            break;
    }
    if((state & (1<<(3-i))) == 0){        //不能打开 
//        cout << state << " " << door << " " << i << " " << (state & (1<<(3-i))) << endl;
        return false;
    }
    return true;
}
原文地址:https://www.cnblogs.com/lighter-blog/p/7308561.html