拯救公主

描述

    多灾多难的公主又被大魔王抓走啦!国王派遣了第一勇士阿福去拯救她。

    身为超级厉害的术士,同时也是阿福的好伙伴,你决定祝他一臂之力。你为阿福提供了一张大魔王根据地的地图,上面标记了阿福和公主所在的位置,以及一些不能够踏入的禁区。你还贴心地为阿福制造了一些传送门,通过一个传送门可以瞬间转移到任意一个传送门,当然阿福也可以选择不通过传送门瞬移。传送门的位置也被标记在了地图上。此外,你还查探到公主所在的地方被设下了结界,需要集齐K种宝石才能打开。当然,你在地图上也标记出了不同宝石所在的位置。

    你希望阿福能够带着公主早日凯旋。于是在阿福出发之前,你还需要为阿福计算出他最快救出公主的时间。

    地图用一个R×C的字符矩阵来表示。字符S表示阿福所在的位置,字符E表示公主所在的位置,字符#表示不能踏入的禁区,字符$表示传送门,字符.表示该位置安全,数字字符0至4表示了宝石的类型。阿福每次可以从当前的位置走到他上下左右四个方向上的任意一个位置,但不能走出地图边界。阿福每走一步需要花费1个单位时间,从一个传送门到达另一个传送门不需要花费时间。当阿福走到宝石所在的位置时,就视为得到了该宝石,不需要花费额外时间。


输入第一行是一个正整数T(1 <= T <= 10),表示一共有T组数据。
每一组数据的第一行包含了三个用空格分开的正整数R、C(2 <= R, C <= 200)和K,表示地图是一个R×C的矩阵,而阿福需要集齐K种宝石才能够打开拘禁公主的结界。
接下来的R行描述了地图的具体内容,每一行包含了C个字符。字符含义如题目描述中所述。保证有且仅有一个S和E。$的数量不超过10个。宝石的类型在数字0至4范围内,即不会超过5种宝石。输出对于每一组数据,输出阿福救出公主所花费的最少单位时间。若阿福无法救出公主,则输出“oop!”(只输出引号里面的内容,不输出引号)。每组数据的输出结果占一行。样例输入
17 8 2..........S..#0..##..1...0#........1#......##E.....1....
样例输出
11

#include 
#include 
#include 
#include 
#include 
using namespace std;

/*
感谢周洋师弟的帮助;
简单的广搜;
*/

struct point
{
    int x, y, s, time;
    point (int xx, int yy, int ss, int tt):x(xx), y(yy), s(ss), time(tt){};
};

struct door
{
    int x, y;
}door[15];

int r,c,k;
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
int min_time = 0;
char mp[210][210];
bool visited[210][210][1 << 5];//记录特定的发现宝石状态下,特定位置的被访问情况;

bool check(int s, int k)
{//s为宝石发现情况;
    int cnt = 0;//记录已发现宝石的个数;
    for (int i = 0; i <= 4; i++)
    {
        if ((s >> i) & 1 == 1)
            cnt++;
    }
    return (cnt >= k);//集齐全部宝石;
}

bool bfs(int x, int y, int ex, int ey, int num_door, int k)
{
    queue qu;
    qu.push(point(x, y, 0, 0));
    while (!qu.empty())
    {
        point temp = qu.front();
        qu.pop();
        if (temp.x == ex && temp.y == ey && check(temp.s, k))
        {
            min_time = temp.time;
            return true;
        }
        if (mp[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 < r && sy >= 0 && sy < c && mp[sx][sy] != '#' && visited[sx][sy][temp.s] == false)
                {
                    visited[sx][sy][temp.s] = true;
                    qu.push(point(sx, sy, temp.s, temp.time + 1));
                }
            }
        }
        if (mp[temp.x][temp.y] >= '0' && mp[temp.x][temp.y] <= '4')
        {
            int s = temp.s | (1 << (mp[temp.x][temp.y] - '0'));
            for (int i = 0; i < 4; i++)
            {
                int sx = temp.x + dx[i];
                int sy = temp.y + dy[i];
                if (sx >= 0 && sx < r && sy >= 0 && sy < c && mp[sx][sy] != '#' && visited[sx][sy][s] == false)
                {
                    visited[sx][sy][s] = true;
                    qu.push(point(sx, sy, s, temp.time + 1));
                }
            }
        }
        if (mp[temp.x][temp.y] == '$')
        {
            for (int i = 0; i < num_door; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    int sx = door[i].x + dx[j];
                    int sy = door[i].y + dy[j];
                    if (sx >= 0 && sx < r && sy >= 0 && sy < c && mp[sx][sy] != '#' && visited[sx][sy][temp.s] == false)
                    {
                        visited[sx][sy][temp.s] = true;
                        qu.push(point(sx, sy, temp.s, temp.time + 1));
                    }
                }
            }
        }
    }
    return false;
}

int main(){
    int t;
    cin >> t;
    while (t--)
    {
        memset(visited,0,sizeof(visited));
        int x, y, ex, ey;
        int cnt = 0;//记录传送门的数量;
        cin >> r >> c >> k;
        for (int i = 0; i < r; i++)
        {
            for (int j = 0; j < c; j++)
            {
                cin >> mp[i][j];
                if (mp[i][j] == '$')
                {
                    door[cnt].x = i;
                    door[cnt].y = j;
                    cnt++;
                }
                if (mp[i][j] == 'S')
                {
                    x = i;
                    y = j;
                    mp[i][j] = '.';
                }
                if (mp[i][j] == 'E')
                {
                    ex = i;
                    ey = j;
                    mp[i][j] = '.';
                }
            }
        }
        if (bfs(x, y, ex, ey, cnt, k))
            cout << min_time << endl;
        else
            cout << "oop!" << endl;
    }
    return 0;
}





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