1、题目:
2、思路:
一开始想的是使用深度优先DFS,但是发现自己不会写(被菜哭了),然后换的是BFS,之前的bfs都是可以统计能够到达的所有格子,但是这题加入左右步数的限制,导致我们并不能直接套模板。
最后一个测试点没过的情况:使用队列,每次加入的元素是位置、剩余的左边步数、剩余的右边步数。这样一个一个加,会发现能过绝大部分,只有最后一个过不了。
满分情况:考虑到同一个位置可能由不同方向过来的情况,如果新的更优的情况剩余的左右步数比之前的更多,我们就更新,否则我们不更新,这里有个容易搞错的点是,我们必须要有左边步数或者有右边步数,我们才能够继续更新没有走过的点。
更新的情况:
1、更新没有走过的点,这时候只要走到这个点的左右剩余步数大于等于0,我们就能对他进行更新
2、剩余的左右步数比之前更大:说明走到这个点的时候,我现在的方向是比之前的方向走过来的要更加优秀。因此更新它,但是由于有st数组记录了被访问过的点,我们不好继续更新,因此这里不引入访问数组st,而是引入两个步数数组。通过比较现在的剩余步数是否比之前的更大来决定是否需要进行访问(入队),这样就避免了访问的一次性。初始的时候所有都要记为负一。
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 2020;
struct xeil
{
int x1,y1,left,right;
};// 分别表示该点得坐标和可以向左和向右移动得次数
// 记录每个位置的最大的left和right
int maxleft[N][N],maxright[N][N];
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,-1,1};
char w[N][N];
bool st[N][N];
int n,m,r,c,x,y;
int ans;
bool is_in(int x,int y)
{
return x>=0&&x<n&&y>=0&&y<m&&w[x][y]!='*';
}
int bfs(int a,int b,int l,int r) {
ans = 1;
queue<xeil> q;
maxleft[a][b] = l;
maxright[a][b] = r;
q.push({a,b,l,r});
while(q.size()) {
auto t = q.front();
q.pop();
for(int i = 0; i < 4; i++) {
int Now_x = t.x1 + dx[i];
int Now_y = t.y1 + dy[i];
int Now_left = t.left - (dy[i] == -1);
int Now_right = t.right - (dy[i] == 1);
if(is_in(Now_x, Now_y)&&Now_left>=0&&Now_right>=0) {
// 检查是否可以提供更多的左/右移动次数
if(Now_left > maxleft[Now_x][Now_y] || Now_right > maxright[Now_x][Now_y]) {
// 如果这是第一次访问,增加计数
if(maxleft[Now_x][Now_y] == -1 && maxright[Now_x][Now_y] == -1)
ans++;
maxleft[Now_x][Now_y] = max(Now_left, maxleft[Now_x][Now_y]);
maxright[Now_x][Now_y] = max(Now_right, maxright[Now_x][Now_y]);
q.push({Now_x, Now_y, Now_left, Now_right});
}
}
}
}
return ans;
}
int main()
{
cin>>n>>m>>r>>c>>x>>y;
for(int i = 0;i<n;i++)
for(int j = 0;j<m;j++)
cin>>w[i][j];
r--;
c--;
memset(maxleft,-1,sizeof maxleft);
memset(maxright,-1,sizeof maxright);
cout<<bfs(r,c,x,y);
return 0;
}