NC 15665 BFS + 优先队列

这篇博客介绍了如何使用BFS(广度优先搜索)和优先队列来解决网格中从起点到终点的最短路径问题。在存在普通移动和传送阵的情况下,通过维护两个队列,分别处理两种移动方式,以找到最短时间。在BFS方法中,使用两个队列按时间顺序更新最短距离;在优先队列方法中,使用优先级队列以广度顺序出队。这两种方法都有效地解决了问题,并给出了相应的C++代码实现。
摘要由CSDN通过智能技术生成
题意

传送门 NC 15665

题解
BFS

考虑到使用传送阵与向相邻格子移动花费的时间不同,用 两个队列 分别维护使用传送阵与向相邻格子移动的情况,每次按照广度递增出队,更新最短时间。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
#define maxn 305
struct P
{
    int x, y;
};
struct node
{
    int x, y, d;
};
int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};
int N, M, Q, sx, sy, tx, ty, dis[maxn][maxn];
char mat[maxn][maxn];
vector<P> door[maxn][maxn];

int main()
{
    while (~scanf("%d%d%d", &N, &M, &Q))
    {
        for (int i = 0; i < N; ++i)
        {
            scanf(" %s", mat + i);
            for (int j = 0; j < M; ++j)
            {
                door[i][j].clear();
                if (mat[i][j] == 'S')
                    sx = i, sy = j;
                if (mat[i][j] == 'T')
                    tx = i, ty = j;
            }
        }
        for (int i = 0; i < Q; ++i)
        {
            int x, y, z, w;
            scanf("%d%d%d%d", &x, &y, &z, &w);
            door[x][y].push_back(P{z, w});
        }
        queue<node> q1, q2;
        memset(dis, -1, sizeof(dis));
        q1.push(node{sx, sy, 0});
        dis[sx][sy] = 0;
        while (dis[tx][ty] == -1 && (!q1.empty() || !q2.empty()))
        {
            int d = q1.empty() ? q2.front().d : q1.front().d;
            while (!q1.empty() && q1.front().d == d)
            {
                node t = q1.front();
                q1.pop();
                for (int i = 0; i < 4; ++i)
                {
                    int nx = t.x + dx[i], ny = t.y + dy[i];
                    if (nx >= 0 && nx < N && ny >= 0 && ny < M && dis[nx][ny] == -1 && mat[nx][ny] != '#')
                    {
                        dis[nx][ny] = d + 1;
                        q1.push(node{nx, ny, d + 1});
                    }
                }
                for (int i = 0; i < (int)door[t.x][t.y].size(); ++i)
                {
                    P &p = door[t.x][t.y][i];
                    if (dis[p.x][p.y] == -1 && mat[p.x][p.y] != '#')
                    {
                        q2.push(node{p.x, p.y, d + 3});
                    }
                }
            }
            while (!q2.empty() && q2.front().d == d)
            {
                node t = q2.front();
                q2.pop();
                dis[t.x][t.y] = t.d;
                for (int i = 0; i < 4; ++i)
                {
                    int nx = t.x + dx[i], ny = t.y + dy[i];
                    if (nx >= 0 && nx < N && ny >= 0 && ny < M && dis[nx][ny] == -1 && mat[nx][ny] != '#')
                    {
                        dis[nx][ny] = d + 1;
                        q1.push(node{nx, ny, d + 1});
                    }
                }
                for (int i = 0; i < (int)door[t.x][t.y].size(); ++i)
                {
                    P &p = door[t.x][t.y][i];
                    if (dis[p.x][p.y] == -1 && mat[p.x][p.y] != '#')
                    {
                        q2.push(node{p.x, p.y, d + 3});
                    }
                }
            }
        }
        printf("%d\n", dis[tx][ty]);
    }
    return 0;
}

BFS + 优先队列

使用优先队列以广度顺序出队即可。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
#define maxn 305
struct P
{
    int x, y;
};
struct node
{
    int x, y, d;
    bool operator<(const node &b) const
    {
        return d > b.d;
    }
};
int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};
int N, M, Q, sx, sy, tx, ty, dis[maxn][maxn];
char mat[maxn][maxn];
vector<P> door[maxn][maxn];

int main()
{
    while (~scanf("%d%d%d", &N, &M, &Q))
    {
        for (int i = 0; i < N; ++i)
        {
            scanf(" %s", mat + i);
            for (int j = 0; j < M; ++j)
            {
                door[i][j].clear();
                if (mat[i][j] == 'S')
                    sx = i, sy = j;
                if (mat[i][j] == 'T')
                    tx = i, ty = j;
            }
        }
        for (int i = 0; i < Q; ++i)
        {
            int x, y, z, w;
            scanf("%d%d%d%d", &x, &y, &z, &w);
            door[x][y].push_back(P{z, w});
        }
        priority_queue<node> q;
        memset(dis, -1, sizeof(dis));
        q.push(node{sx, sy, 0});
        while (!q.empty())
        {
            node t = q.top();
            q.pop();
            dis[t.x][t.y] = t.d;
            if (t.x == tx && t.y == ty)
                break;
            for (int i = 0; i < 4; ++i)
            {
                int nx = t.x + dx[i], ny = t.y + dy[i];
                if (nx >= 0 && nx < N && ny >= 0 && ny < M && dis[nx][ny] == -1 && mat[nx][ny] != '#')
                {
                    dis[nx][ny] = t.d + 1;
                    q.push(node{nx, ny, t.d + 1});
                }
            }
            for (int i = 0; i < (int)door[t.x][t.y].size(); ++i)
            {
                P &p = door[t.x][t.y][i];
                if (dis[p.x][p.y] == -1 && mat[p.x][p.y] != '#')
                {
                    q.push(node{p.x, p.y, t.d + 3});
                }
            }
        }
        printf("%d\n", dis[tx][ty]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值