给定一个 \(n \times m\) 地图,每个格子为空地或墙,你从一个位置开始,四连通移动,向上向下次数不限,向左最多 \(x\) 次,向右最多 \(y\) 次,问能到达多少个格子

Solution

如果只有一个方向有代价,那么简单 BFS 即可

然而这里两个方向都有代价,但是点 \((r,c) \to (i,j)\) 的横坐标差是确定的,换言之,如果设向左走了 \(a\) 步,那么向右走的步数就是 \(i-r+a\)

于是我们只对向左的边设代价即可,最终在考虑 \((r,c) \to (i,j)\) 的过程时,同时要求 $a \leq x $ 和 $ j-c+a \leq y$ 即可

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

const int N = 2005;

const int di[4] = {1,-1,0,0}, dj[4] = {0,0,1,-1};
int n,m,r,c,x,y,f[N][N],v[N][N];
char a[N][N];

struct point {int i,j;};

int ok(int i,int j) {
    if(i>=1 && j>=1 && i<=n && j<=m && a[i][j]=='.') return 1;
    return 0;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m>>r>>c>>x>>y;
    for(int i=1;i<=n;i++) {
        cin>>a[i]+1;
    }
    memset(f,0x3f,sizeof f);
    f[r][c]=0;
    deque <point> q;
    q.push_back({r,c});
    while(q.size()) {
        int i=q.front().i, j=q.front().j;
        q.pop_front();
        for(int k=0;k<4;k++) {
            int ni=i+di[k],nj=j+dj[k];
            if(ok(ni,nj)) {
                if(k<3) {
                    f[ni][nj]=min(f[ni][nj],f[i][j]);
                    if(v[ni][nj]<2) {
                        v[ni][nj]=2;
                        q.push_front({ni,nj});
                    }
                }
                else {
                    f[ni][nj]=min(f[ni][nj],f[i][j]+1);
                    if(!v[ni][nj]) {
                        v[ni][nj]=1;
                        q.push_back({ni,nj});
                    }
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            if(f[i][j]<=x && j-c+f[i][j]<=y) ++ans;
        }
    }
    cout<<ans;
}

相关文章: