AcWing 4481. 方格探索 双端队列bfs 最短路

题目

在这里插入图片描述

题解思路

如果我们能表达出到达每个点最小的向左数以及向右数,那么这个题目就很容易写出来了。
试探看看有没有性质(也就是向右数和向左数有没有关系)
我们先假设最小向右数为tp,最小向左数为tp2。当我们走到的格子纵坐标为 j , 起点纵坐标为 sy 。向右可走xx,向左可走yy 。
可以推出
此时的向左数为 tp3 = tp - ( j - sy ) 。
根据单调性可得tp2==tp3.
所以我们只需求出到达每个点的向右走的最小值即可。
由于是01费用的路径。直接使用双端队列bfs,有费用放队尾,无费用放队头。
很巧妙。

AC代码
/*从你的全世界路过.*/
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long

using namespace std;

const  int  INF =  0x3f3f3f3f;
const  int  N =  200100;
int n , m ;
int xx , yy ; 
int sx , sy ; 
char g[2010][2010] ; 
int dx[4] = {0,0,-1,1} ; 
int dy[4] = {1,-1,0,0} ;
int dis[2010][2010] ;  
int vis[2010][2010] ; 
void bfs()
{
    deque <PII> q ; 
    memset(dis,0x3f,sizeof(dis)) ; 
    dis[sx][sy] = 0 ; 
    q.push_back({sx,sy}) ; 
    while (!q.empty())
    {
        auto sk = q.front() ;
        q.pop_front();
        if ( vis[sk.first][sk.second] )
            continue;
        vis[sk.first][sk.second] = 1 ; 
        for (int i = 0 ; i < 4 ; i++ )
        {
            int fx = sk.first + dx[i] ; 
            int fy = sk.second + dy[i] ; 
            if ( fx >= 1 && fx <= n && fy >= 1 && fy <= m && g[fx][fy] != '*' )
            {
                if ( i == 0 )
                {
                    if ( dis[fx][fy] > dis[sk.first][sk.second] + 1 )
                    dis[fx][fy] = dis[sk.first][sk.second] + 1 , q.push_back({fx,fy}) ; 
                }
                else
                {
                    if ( dis[fx][fy] > dis[sk.first][sk.second] )
                        dis[fx][fy] = dis[sk.first][sk.second] , q.push_front({fx,fy}) ; 
                }
            }
        }
    }
}
void solve()
{
    cin >> n >> m ;
    cin >> sx >> sy ;
    cin >> xx >> yy ; 
    for (int i = 1 ; i <= n ; i++ )
        cin >> g[i] + 1 ;
    bfs();
    int cnt = 0 ; 
    for (int i = 1 ; i <= n ; i++ )
        for (int j = 1 ; j <= m ; j++ )
        {
            int tp = dis[i][j] ; 
            if ( tp <= yy && tp - (j - sy) <= xx )
                cnt++;
        }
    cout << cnt << "\n" ; 
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        solve() ;
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值