• 方格探索(双端队列)


    题意

    给定一个\(n\)\(m\)列的方格矩阵。行坐标从上到下为\(1 \sim n\),列坐标从左到右为\(1 \sim m\)。其中的每个方格,要么是空格(用.表示),要么包含障碍物(用*表示)。

    初始时,一个人位于第\(r\)行第\(c\)列的空格之中。他可以沿上下左右四个方向进行移动,每次移动一格距离。

    对于他的移动,有如下限制:

    • 他不能进入到包含障碍物的方格中,也不能走出矩阵的边界。
    • 在整个移动过程中,他向左移动的总次数不能超过\(x\)次。
    • 在整个移动过程中,他向右移动的总次数不能超过\(y\)次。

    请问,一共有多少个空格是此人可以抵达的?注意,初始空格视为此人可达。

    题目链接:https://www.acwing.com/problem/content/4484/

    数据范围

    \(1 \leq n, m \leq 2000\)
    \(0 \leq x, y \leq 10^9\)

    思路

    首先想到的是利用分层图求解,但是由于\(x, y\)太大,因此时空复杂度都不满足条件,因此考虑如何进行优化。

    我们可以先考虑一个简单的问题,只对向左移动的总次数有限制,对向右移动次数没有限制。

    这个问题是一个最短路问题,向左走时边权为\(1\),其他方向边权为\(0\)。注意:在BFS时要使用双端队列,维护一个st数组,同时将向左走的总次数传入队列中。

    现在回到原来的问题。如何才能同时处理左右都有限制的情况呢?

    我们发现一个性质,从\((r, c)\)走到任意一个点\((i, j)\),有着\(right - left = j - c\)恒成立,其中\(right\)为向右走的步数,\(left\)为向左走的步数。因此,向左走的总次数最短,意味着向右走的总次数也是最短的。因此,比起简化版的问题,只需要在队列中同时传入向左走的总次数和向右走的总次数。

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    
    #define x first
    #define y second
    
    using namespace std;
    
    typedef pair<int, int> pii;
    typedef pair<pii, pii> ppp;
    
    const int N = 2010;
    
    int n, m, r, c, L, R;
    char g[N][N];
    bool st[N][N];
    
    int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
    
    void bfs()
    {
        deque<ppp> que;
        que.push_back({{r, c}, {0, 0}});
        st[r][c] = true;
        while(que.size()) {
            auto t = que.front();
            que.pop_front();
            int tx = t.x.x, ty = t.x.y;
            for(int i = 0; i < 4; i ++) {
                int x = tx + dx[i], y = ty + dy[i];
                if(x < 1 || x > n || y < 1 || y > m) continue;
                if(g[x][y] == '*') continue;
                if(st[x][y]) continue;
                if(i == 0 || i == 1) {
                    que.push_front({{x, y}, {t.y.x, t.y.y}});
                    st[x][y] = true;
                }
                else if(i == 2) {
                    if(t.y.x + 1 > L) continue;
                    que.push_back({{x, y}, {t.y.x + 1, t.y.y}});
                    st[x][y] = true;
                }
                else {
                    if(t.y.y + 1 > R) continue;
                    que.push_back({{x, y}, {t.y.x, t.y.y + 1}});
                    st[x][y] = true;
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d%d%d%d%d%d", &n, &m, &r, &c, &L, &R);
        for(int i = 1; i <= n; i ++) scanf("%s", g[i] + 1);
        bfs();
        int ans = 0;
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m; j ++) {
                if(st[i][j]) {
                    ans ++;
                }
            }
        }
        printf("%d\n", ans);
        return 0;
    }
    
  • 相关阅读:
    JQuery EasyUi之界面设计——通用的JavaScript
    easyui datagrid 行右键 动态获取并生成toolbar 按钮
    Jq基础拓展 json to String
    电信光纤猫(HG8245)破解教程 开启无线网、路由器功能(第二章)
    plsql 无需配置客户端连接.
    中文分词常用算法之基于词典的正向最大匹配
    中文分词常用算法之基于词典的逆向最大匹配
    SQL SERVER安装序列号
    查询锁事务及语句
    SQL Server 数据库备份
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/16368096.html
Copyright © 2020-2023  润新知