Saving Tang Monk

描述

《Journey to theWest》(also 《Monkey》) is one of the Four Great Classical Novelsof Chinese literature. It was writtenby Wu Cheng'en during the Ming Dynasty. In this novel, Monkey King Sun Wukong,pig Zhu Bajie and Sha Wujing, escorted Tang Monk to India to getsacred Buddhism texts.

During thejourney, Tang Monk was often captured by demons. Most of demons wanted to eatTang Monk to achieve immortality, but some female demons just wanted to marryhim because he was handsome. So, fighting demons and saving Monk Tang is themajor job for Sun Wukong to do.

Once, TangMonk was captured by the demon White Bones. White Bones lived in a palace andshe cuffed Tang Monk in a room. Sun Wukong managed to get into the palace. Butto rescue Tang Monk, Sun Wukong might need to get some keys and kill some snakesin his way.

The palace can be described as a matrix of characters. Each characterstands for a room. In the matrix, 'K' represents the original position of SunWukong, 'T' represents the location of Tang Monk and 'S' stands for a room witha snakein it. Please note that there are only one 'K' and one 'T', and at mostfive snakesin the palace. And, '.' means a clear room as well '#' means a deadlyroom which Sun Wukong couldn't get in.

There may be some keys of different kinds scattered in the rooms, butthere is at most one key in one room. There are at most 9 kinds of keys. A roomwith a key in it is represented by a digit(from '1' to '9'). For example, '1'means a room with a first kind key, '2' means a room with a second kind key,'3' means a room with a third kind key... etc. To save Tang Monk, Sun Wukongmust get ALL kinds of keys(in other words, at least one key for each kind).

For each step, Sun Wukong could moveto the adjacent rooms(except deadly rooms) in 4 directions(north,west,south andeast), and each step took him one minute. If he entered a room in which a livingsnakestayed, he must kill the snake. Killinga snakealso took one minute. If Sun Wukong entered aroom where there is a key of kind N, Sun would get that key if and only if hehad already got keys of kind 1,kind 2 ... and kind N-1.In other words,Sun Wukong must get a key of kind N before he could get a key of kind N+1 (N>=1).If Sun Wukong got all keys he needed and entered the room in which Tang Monkwas cuffed, the rescue mission is completed. If Sun Wukong didn't get enough keys,he still could pass through Tang Monk's room. Since Sun Wukong was a impatient monkey,he wanted to save Tang Monk as quickly as possible. Please figure out theminimum time Sun Wukong needed to rescue Tang Monk.

    

输入
There are several test cases.
For each case, the first line includes two integers N and M(0 < N <= 100, 0<=M<=9), meaning that the palace is a N * N matrix and Sun Wukong needed M kinds of keys(kind 1, kind 2, ... kind M). 
Then the N*N matrix follows.
The input ends with N = 0 and M = 0.
输出
For each test case, print the minimum time (in minute) Sun Wokong needed to save Tang Monk. If it's impossible for Sun Wokong to complete the mission, print "impossible".
样例输入
3 1
K.S
##1
1#T
3 1
K#T
.S#
1#.
3 2
K#T
.S.
21.
0 0
样例输出
5
impossible
8


关于位运算,参考:

http://blog.csdn.net/Stand_over_sun/article/details/8083276

http://www.cnblogs.com/flying_bat/archive/2008/06/17/1224178.html


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

/*
感谢周洋师弟的帮助;
使用广搜,使用位运算巧妙表示蛇的状态;
*/

int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

struct node{//记录特定位置的信息
    int x, y, s, key, time;//s表示蛇的状态,key表示钥匙;
    node(int xx, int yy, int ss, int kk, int tt): x(xx), y(yy), s(ss), key(kk), time(tt){};
};

struct point_snake{//记录蛇所在的点;
    int x, y;
    point_snake(int xx, int yy): x(xx), y(yy){};
};

bool operator == (point_snake s1, point_snake s2)//cul_snake_num函数中find所使用的二分搜索所用到的比较器;
{
    return (s1.x == s2.x && s1.y == s2.y);
}

int N, M, min_time;
char maze[110][110];
bool visited[110][110][1 << 5][10];//记录特定位置的被访问情况;
//1 << 5记录5条蛇的状态
vector<point_snake> vec;

int cul_snake_num(int x, int y)
{//计算这是第几条蛇;
    return find(vec.begin(),vec.end(),point_snake(x, y)) - vec.begin();//从0记起;
}

bool BFS(int x, int y, int ex, int ey)
{
    queue<node> qu;//记录通路;
    qu.push(node(x, y, 0, 0, 0));
    while (!qu.empty())
    {
        node temp = qu.front();//当前步广搜的出发点;
        if (temp.x == ex && temp.y == ey && temp.key == M)
        {//收集齐所有钥匙,来到唐僧所在房间;
            min_time = temp.time;//时间被记录在node内;
            return true;
        }
        if (maze[temp.x][temp.y] == '.')
        {//遇到平路,直接走过去;
            for (int i = 0; i < 4; i++)
            {
                int sx = temp.x + dx[i];
                int sy = temp.y + dy[i];
                if (sx >= 0 && sx <= N - 1 && sy >= 0 && sy <= N - 1 && maze[sx][sy] != '#' && visited[sx][sy][temp.s][temp.key] == false)//朝该方向走是可行的;
                {
                    qu.push(node(sx, sy, temp.s, temp.key, temp.time + 1));//计入通路中;
                    visited[sx][sy][temp.s][temp.key] = true;//标记此地被访问;
                }
            }
        }
        if (maze[temp.x][temp.y] == 'S')
        {//遇到蛇,判断之前是否已杀死;
            int num = cul_snake_num(temp.x, temp.y);//计算这是第几条蛇;
            //蛇的初始状态被储存为100000;第0条蛇被杀死,记为100001;
            //可以通过(temp.s >> num) & 1 的值来判断蛇的生死;
            //例如,第0条蛇被杀死,s = 100001, (s >> 0) & 1 = 000001 = 1;
            if ((temp.s >> num) & 1 == 1)
            {
                for (int i = 0; i < 4; i++)
                {
                    int sx = temp.x + dx[i];
                    int sy = temp.y + dy[i];
                    if (sx >= 0 && sx <= N - 1 && sy >= 0 && sy <= N - 1 && maze[sx][sy] != '#' && visited[sx][sy][temp.s][temp.key] == false)//朝该方向走是可行的;
                    {
                        qu.push(node(sx, sy, temp.s, temp.key, temp.time + 1));//计入通路中;
                        visited[sx][sy][temp.s][temp.key] = true;//标记此地被访问;
                    }
                }
            }
            else
            {//蛇没有被杀死;
                int s = (temp.s) | (1 << num);//记录新的蛇状态;
                //例如,初始状态为100000,遇到第0条,杀;
                //100000 | (1 << 0) = 100000 | 000001 = 100001;
                //这就是新的蛇状态;
                qu.push(node(temp.x, temp.y, s, temp.key, temp.time + 1));
                visited[temp.x][temp.y][s][temp.key] = true;
            }
        }
        if (maze[temp.x][temp.y] >= '1' && maze[temp.x][temp.y] <= '9')
        {//遇到钥匙;
            int key_num = maze[temp.x][temp.y] - '0';
            if (key_num == temp.key + 1)
            {//遇到对的钥匙;
                for (int i = 0; i < 4; i++)
                {
                    int sx = temp.x + dx[i];
                    int sy = temp.y + dy[i];
                    if (sx >= 0 && sx <= N - 1 && sy >= 0 && sy <= N - 1 && maze[sx][sy] != '#' && visited[sx][sy][temp.s][temp.key + 1] == false)//朝该方向走是可行的;
                    {
                        qu.push(node(sx, sy, temp.s, temp.key + 1, temp.time + 1));//计入通路中;
                        visited[sx][sy][temp.s][temp.key + 1] = true;//标记此地被访问;
                    }
                }
            }
            else
            {//遇到不对的钥匙;
                for (int i = 0; i < 4; i++)
                {
                    int sx = temp.x + dx[i];
                    int sy = temp.y + dy[i];
                    if (sx >= 0 && sx <= N - 1 && sy >= 0 && sy <= N - 1 && maze[sx][sy] != '#' && visited[sx][sy][temp.s][temp.key] == false)//朝该方向走是可行的;
                    {
                        qu.push(node(sx, sy, temp.s, temp.key, temp.time + 1));//计入通路中;
                        visited[sx][sy][temp.s][temp.key] = true;//标记此地被访问;
                    }
                }
            }
        }
        qu.pop();
    }
    return false;
}

int main(){
    cin >> N >> M;
    while (N != 0 || M != 0)
    {
        int kx, ky, tx, ty;//孙悟空和唐僧的位置;
        vec.clear();
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                cin >> maze[i][j];
                char c = maze[i][j];
                if (c == 'K')
                {
                    kx = i;
                    ky = j;
                    maze[i][j] = '.';//通途;
                }
                if (c == 'T')
                {
                    tx = i;
                    ty = j;
                    maze[i][j] = '.';//通途;
                }
                if (c == 'S')
                {
                    vec.push_back(point_snake(i, j));
                }
            }
        }
        memset(visited, 0, sizeof(visited));
        if (BFS(kx, ky, tx, ty))
            cout << min_time << endl;
        else
            cout << "impossible" << endl;
        cin >> N >> M;
    }
    return 0;
}


你可能感兴趣的:(广搜)