[01BFS] Codeforces-1063B Labyrinth

1063B Labyrinth

题目

        你有一个n\times m大小的迷宫,迷宫中“.”代表可以前进,“*”代表无法前进。你要统计在对上下移动没有要求,但是左右移动有最大次数限制的情况下,最多有多少个格子能被到达。起点由题目给定。

思路

        首先我们发现对于同一列的元素来说,它们还可以向左右移动的次数是完全相同的。而对于某一个元素的左右两个元素来说,它们是否可以被到达,取决于这个中心元素的左右移动次数是否有剩余。那么我们可以发现01BFS的性质:对于一些选项,权值是0,而其他的选项为1。

        我们将向上和向下移动的权值设为0,左右移动设为1,按照权值小的元素优先的原则维护双端队列即可。(对于那些可以从两条消耗不同权值的路径到达的格子,我们的通过BFS来让消耗最小的方法最快到达。)

        01BFS:对于最短路算法,我们可以使用优先队列优化,但是如果边的权值只有0和1,那么优先队列就有些浪费,我们可以使用双端队列来维护类似优先队列的性质。具体来说,对于某个只有0和1权值的图,我们将0权值从队首入队,1权值的从队尾入队,这样在双端队列中,时刻都保持着“两段性”和“单调性”,这样就可以快速的求解最短路问题了。某些节点可能会多次进入队列中,但是只有第一次出队时才有价值,之后可以忽略。

代码

#include <bits/stdc++.h>
using namespace std;

#define MAXN 2003

int n, m;
int xs, ys;
int tml, tmr;
char g[MAXN][MAXN];
int cx[4] = {0, 1, 0, -1}, cy[4] = {1, 0, -1, 0}; //向哪里前进(右,下,左,上)
struct PII { int x, y; }; //双向队列的数据结构
int dist[MAXN][MAXN][2]; //记录这个点还剩多少权值
bool st[MAXN][MAXN]; //记录是否走过这条边
int Deque_BFS () {
    memset(dist, 0, sizeof(dist));
    dist[xs][ys][0] = tml; dist[xs][ys][1] = tmr; //开始的地方有着原始的权值
    memset(st, 0, sizeof(st));
    deque<PII> dq;
    dq.push_front({xs, ys});
    while (dq.size() > 0) {
        PII tmp = dq.front();
        dq.pop_front();
        if (st[tmp.x][tmp.y] == true) continue;
        st[tmp.x][tmp.y] = true; //记录已经走过的点
        for (int i=0; i<4; i++) { //尝试每一种情况
            int x = tmp.x+cx[i], y = tmp.y+cy[i];
            if (x<=0 || x>n || y<=0 || y>m || g[x][y]=='*' || st[x][y]==true) continue; //边界
            if (i==1 || i==3) { //上下
                dist[x][y][0] = dist[tmp.x][tmp.y][0];
                dist[x][y][1] = dist[tmp.x][tmp.y][1];
                dq.push_front({x, y});
            }
            else if (i == 0) { //右
                if (dist[tmp.x][tmp.y][1] < 1) continue;
                dist[x][y][0] = dist[tmp.x][tmp.y][0];
                dist[x][y][1] = dist[tmp.x][tmp.y][1] - 1;
                dq.push_back({x, y});
            }
            else if (i == 2) { //左
                if (dist[tmp.x][tmp.y][0] < 1) continue;
                dist[x][y][0] = dist[tmp.x][tmp.y][0] - 1;
                dist[x][y][1] = dist[tmp.x][tmp.y][1];
                dq.push_back({x, y});
            }
        }
    }
    int ans = 0;
    for (int i=1; i<=n; i++) {
        for (int j=1; j<=m; j++) {
            if (st[i][j] == 1) ans++;
        }
    } //最后统计一下这张图上有多少点被标记过
    return ans;
}

int main () {
    while (scanf("%d %d", &n, &m) != EOF) {
        scanf("%d %d", &xs, &ys);
        scanf("%d %d", &tml, &tmr);
        for (int i=1; i<=n; i++) {
            scanf("%s", g[i]+1);
        }
        printf("%d\n", Deque_BFS());
    }
}

        上传前尝试过了,能Accept。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值