题目
题解思路
如果我们能表达出到达每个点最小的向左数以及向右数,那么这个题目就很容易写出来了。
试探看看有没有性质(也就是向右数和向左数有没有关系)
我们先假设最小向右数为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 ;
}