《巫妖王的远征》(bfs板子题)

下午要打工作室例赛,会考察搜索内容,搜索本来也忘得差不多了,于是想找点题练练手,正好昨天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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值