多灾多难的公主又被大魔王抓走啦!国王派遣了第一勇士阿福去拯救她。
身为超级厉害的术士,同时也是阿福的好伙伴,你决定祝他一臂之力。你为阿福提供了一张大魔王根据地的地图,上面标记了阿福和公主所在的位置,以及一些不能够踏入的禁区。你还贴心地为阿福制造了一些传送门,通过一个传送门可以瞬间转移到任意一个传送门,当然阿福也可以选择不通过传送门瞬移。传送门的位置也被标记在了地图上。此外,你还查探到公主所在的地方被设下了结界,需要集齐K种宝石才能打开。当然,你在地图上也标记出了不同宝石所在的位置。
你希望阿福能够带着公主早日凯旋。于是在阿福出发之前,你还需要为阿福计算出他最快救出公主的时间。
地图用一个R×C的字符矩阵来表示。字符S表示阿福所在的位置,字符E表示公主所在的位置,字符#表示不能踏入的禁区,字符$表示传送门,字符.表示该位置安全,数字字符0至4表示了宝石的类型。阿福每次可以从当前的位置走到他上下左右四个方向上的任意一个位置,但不能走出地图边界。阿福每走一步需要花费1个单位时间,从一个传送门到达另一个传送门不需要花费时间。当阿福走到宝石所在的位置时,就视为得到了该宝石,不需要花费额外时间。
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;
}