「KDOI-01」醉花阴
题目背景
最近,kdy迷上了一款游戏。在游戏里,他扮演着一只逍遥自在的大白鹅。
现在,他正在控制着大白鹅完成最终的任务。
题目描述
大白鹅现在位于一个 n*m 的迷宫中,迷宫由数字 0 和 1 组成,若某一格上的数为 0,则表示该处可以通行,若为 1,则表示该处不可通行。刚开始,它位于 (a,b) 的位置,而出口在 (c,d)。矩阵左上角坐标是 (1,1),右下角坐标是 (n,m)。
不巧的是,这个迷宫里有 k 个猎手,他们会对大白鹅造成威胁。当两者坐标相同时,大白鹅就会被抓住,无论是在入口还是出口。
猎手和大白鹅每秒都能移动一个单位,当然他们也可以不移动。两者同时开始移动且他们都只能向上下左右四个方向移动。现在他想知道,大白鹅有没有可能在不被猎手抓到的情况下走出迷宫,我们假设这些猎手都足够聪明。
kdy 想让你帮他算算,大白鹅能不能逃出迷宫。因为 kdyl 还要玩二周目,所以他只给了你 500ms 的时间。
输入格式
本题有多组数据,第一行一个正整数 t,为数据组数。接下来 t 组数据,其中对于每一组数据:
第一行两个正整数 n 和 m。
接下来输入一个 n 行 m 列的矩阵,矩阵只会由 0 和 1 组成。
紧接着是一个整数 k,表示猎手数目。
接下来 k 行,每行两个正整数,表示 k 个猎手的初始坐标。
最后一行四个整数 a,b,c,d,表示入口和出口的坐标。
本题涉及的所有坐标都在地图内且不会位于障碍处。
输出格式
对于每一组数据,如果大白鹅可以成功走出迷宫且不被抓到,输出 'T',否则输出 'F'。
样例 1
样例输入 1
2
3 4
0100
0011
1001
2
1 1
1 4
2 2 3 2
2 2
01
10
0
1 1 2 2
样例输出 1
T
F
提示
样例解释:
对于第一组数据,画出示意图如下:
大白鹅明显不会被追上。
对于第二组数据,大白鹅不可能到达终点。
本题采用捆绑数据测试。
- Subtask 0(10 pts):k=0。
- Subtask 1(10 pts):n,m<=10。
- Subtask 2(30 pts):k<=10^2。
- Subtask 3(50 pts):无特殊限制。
对于全部数据,n,m<=10^3,k<=n*m,t<=10。
首先如果存在一条路能让大白鹅到终点(先不考虑猎人),我们在考虑猎人。
否则不存在一条路能让大白鹅到终点直接输出‘F’就行。
因为用的bfs搜索,我们一步一步找到大白鹅到终点的路径,如果猎人的路径大于大白鹅到终点的路径,就追不上大白鹅。(我们可以假设这样的模型,大白鹅和猎人在一条笔直的赛道上赛跑,他们速度相等,就看谁离终点进,谁就获胜,你可以在草稿纸上画出示意图)
那么接下来就是套bfs的模板了,不了解bfs的可以看我之前的博客*/
下面上代码
#include <iostream>
#include <string>
#include <queue>
#include <cstring>
using namespace std;
int max_step1 = 0;
int temp_step1 = 0;
int n, m;
bool vis[1000][1000];
string maze[1000];
int hunterx[1000000];
int huntery[1000000];
int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; /*方向*/
int start_x, start_y, end_x, end_y;
struct node /*结构体*/
{
int x, y, step;
node(int _x, int _y, int _step)
{
x = _x;
y = _y;
step = _step;
}
};
void speed() /*使cin具有scanf一样的速度*/
{
ios_base::sync_with_stdio(false);
cin.tie(0);
}
bool in(int x, int y) /*是否越界*/
{
return x >= 0 && x < n && y >= 0 && y < m;
}
bool bfs1(int x, int y) /*广度搜索*/
{
queue<node> q;
q.push(node(x, y, 0));
vis[x][y] = 1;
while (!q.empty())
{
node temp = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int tx = temp.x + dir[i][0];
int ty = temp.y + dir[i][1];
if (in(tx, ty))
{
if (maze[tx][ty] != '1' && !vis[tx][ty])
{
if (tx == end_x && ty == end_y)
{
max_step1 = temp.step + 1; /*如果能到终点就把到终点的步数拿出来*/
return true;
}
else
{
vis[tx][ty] = 1;
q.push(node(tx, ty, temp.step + 1));
}
}
}
}
}
return false;
}
bool bfs2(int x, int y)
{
queue<node> q;
q.push(node(x, y, 0));
vis[x][y] = 1;
if (x == start_x && y == start_y) /*防止特例*/
{
return true;
}
while (!q.empty())
{
node temp = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int tx = temp.x + dir[i][0];
int ty = temp.y + dir[i][1];
if (in(tx, ty))
{
if (maze[tx][ty] != '1' && !vis[tx][ty])
{
if (tx == end_x && ty == end_y)
{
temp_step1 = temp.step + 1; /*猎人到终点的距离*/
return true;
}
else
{
vis[tx][ty] = 1;
q.push(node(tx, ty, temp.step + 1));
if (temp.step + 1 > max_step1) /*剪枝*/
{
return false;
}
}
}
}
}
}
return false;
}
int main()
{
speed();
int t;
cin >> t;
while (t > 0)
{
cin >> n >> m;
bool flag = true;
memset(vis, 0, sizeof(vis));
max_step1 = 0;
for (int i = 0; i < n; i++)
{
cin >> maze[i];
}
int k;
cin >> k;
for (int i = 0; i < k; i++)
{
cin >> hunterx[i] >> huntery[i];
hunterx[i]--;
huntery[i]--;
}
cin >> start_x >> start_y >> end_x >> end_y;
start_x--;
start_y--;
end_x--;
end_y--;
if (start_x == end_x && start_y == end_y)
{
cout << 'T' << endl;
}
else
{
if (bfs1(start_x, start_y) == false) /*如果大白鹅到不了终点*/
{
cout << 'F' << endl;
}
else
{
for (int i = 0; i < k; i++)
{
memset(vis, 0, sizeof(vis));
temp_step1 = 0;
if (bfs2(hunterx[i], huntery[i]) == true && temp_step1 <= max_step1) /*如果猎人比大白鹅到的更快*/
{
flag = false;
cout << 'F' << endl;
break;
}
}
if (flag == true)
{
cout << 'T' << endl;
}
}
}
t--;
}
return 0;
}