下午要打工作室例赛,会考察搜索内容,搜索本来也忘得差不多了,于是想找点题练练手,正好昨天xbl在补很早之前牛客上的一道bfs题,于是今天写了一下。、
题目链接:传送门
“他的邪恶乃是一个传奇。他是亡灵天灾的君王,是符文圣剑霜之哀伤的主人,是艾泽拉斯世界一切自由族类的大敌。
巫妖王是无与伦比的强大力量与极端冷酷的化身,他比寒冰更加寒冷的灵魂已经被他的宏大计划彻底吞噬。
在这个计划中,他将毁灭世界上的全部生灵。
巫妖王-阿尔萨斯已经启动了可能导致艾泽拉斯所有生灵毁灭的计划,他的天灾军团和驱役亡灵的强大力量将横扫整个世界。
我们可以将艾泽拉斯视为n∗m的矩阵,其中
S:寒冰王座,起点
T:暴风城,终点
∗:平原,天灾军团可以到达的地方
#:沼泽,天灾军团无法到达的地方
在地图上存在着 k 个传送门,借助传送门,可以瞬间(不花费时间地)从传送门的任一端到达另一端
天灾军团每小时可以向其周围4个方向移动一格(上下左右),为了保证天灾军团随时保持最高战斗力,巫妖王命令军队每行军8小时,就原地休息1小时。
现在巫妖王率领他的天灾军团从S出发,问最快多久可以到达T?
输入描述:
第1行两个整数n,m (1<= n, m<=1000 , 且n,m不同时等于1)
第2到n+1行每行含有m个字符,其中:
第n+2行有一个整数k(0 <= k <= 10)
随后k行,每行包含4个整数x1,y1,x2,y2表示传送门两端的
坐标(x1,y1),(x2,y2)(1 <= x1,x2 <= n ,1<= y1,y2<= m)
(注意,传送门也可以直接存在于S和T之间,同时,同一个传送门的两
端可能在同一个位置,但是一个地点不可能有多个传送门的一端)
输出描述:
输出仅一行,表示巫妖王到达暴风城的最短时间,如果无法到达,
则输出-1
这道题是一个很显然的bfs题,主要是增加了传送门、休息时间这两个点,不过还是有挺多的细节问题需要注意。不然也不会卡我近两个小时
先看题目,讲一下两个点
1.每行军8小时休息一小时,也就是说每满八小时要加一小时
。如果设不休息时的答案为ans,那么休息时的答案就为ans=ans+ans/8,当然,如果在第k个8小时刚好抵达
,那就不需要休息了,ans还要减1。
2.传送门。这个传送门没有规定方向,所以是双向传送门,即可以从a端传送到b端,也可以从b端传送到a端。另外需要特别注意的是,传送门的一端可能在沼泽地
。另外,使用过的传送门是肯定不会二次使用的
,这里可以思考一下。还有我觉得题目的传送门坐标越界了。。。
其它的差不多就是bfs模板了
上AC代码:
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <queue>
#include <deque>
#include <cstring>
#include <iterator>
#include <set>
using namespace std;
#define ll long long
char mp[1005][1005];
int vis[1005][1005];
int cs[12][4];
int ans, flag;
int mov[4][2] = {1, 0, -1, 0, 0, -1, 0, 1};
int sx, sy, ex, ey;
struct haha
{
int x, y, step;
} a, b;
queue<haha> q;
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
scanf("%s", mp[i] + 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (mp[i][j] == 'S')
{
a.x = i;
a.y = j;
a.step = 0;
q.push(a);
}
else if (mp[i][j] == 'T')
{
ex = i;
ey = j;
}
int k;
scanf("%d", &k);
for (int i = 0; i < k; i++)
{
scanf("%d %d %d %d", &cs[i][0], &cs[i][1], &cs[i][2], &cs[i][3]);
if (cs[i][0] <= 0 || cs[i][0] > n || cs[i][1] <= 0 || cs[i][1] > m || cs[i][2] <= 0 || cs[i][2] > n || cs[i][3] <= 0 || cs[i][3] > m)
{
cs[i][0] = -1;
cs[i][2] = -1;
}
else if (mp[cs[i][0]][cs[i][1]] == '#' || mp[cs[i][2]][cs[i][3]] == '#')
{
cs[i][0] = -1;
cs[i][2] = -1;
}
}
for (int i = 0; i < k; i++)
{
if ((a.x == cs[i][0] && a.y == cs[i][1]) && (ex == cs[i][2] && ey == cs[i][3]))
{
printf("0\n"); //如果传送门a端与起点重合,并且b端与终点重合,直接抵达。
return 0;
}
else if ((a.x == cs[i][2] && a.y == cs[i][3]) && (ex == cs[i][0] && ey == cs[i][1]))
{
printf("0\n"); //如果传送门b端与起点重合,并且a端与终点重合,直接抵达。
return 0;
}
}
while (!q.empty())
{
a = q.front();
q.pop();
if (a.x == ex && a.y == ey)
{
flag = 1;
ans = a.step + a.step / 8; //考虑休息时间
if (a.step % 8 == 0)
ans--;
printf("%d\n", ans);
break;
}
for (int i = 0; i < 4; i++)
{
int xx = a.x + mov[i][0];
int yy = a.y + mov[i][1];
if (xx <= 0 || yy <= 0 || xx > n || yy > m || vis[xx][yy] || mp[xx][yy] == '#')
continue;
for (int j = 0; j < k; j++) //到达传送门的点也要压入队列
if (xx == cs[j][0] && yy == cs[j][1])
{
b.x = cs[j][2];
b.y = cs[j][3];
b.step = a.step + 1;
q.push(b);
vis[b.x][b.y] = 1; //传送过去了就不用了回来了~~~
}
else if (xx == cs[j][2] && yy == cs[j][3]) //同上
{
b.x = cs[j][0];
b.y = cs[j][1];
b.step = a.step + 1;
q.push(b);
vis[b.x][b.y] = 1;
}
vis[xx][yy] = 1;
b.x = xx;
b.y = yy;
b.step = a.step + 1;
q.push(b);
}
}
if (!flag) //如果最后抵达
printf("-1\n");
return 0;
}