CF1064D. Labyrinth

给出一个$𝑛×𝑚$的网格,给出起始点,要求向左走不超过𝐿步,向右走不超过𝑅步,求出能遍历到哪些点。

$01BFS$模版题。

直接$bfs$会出现问题,因为一旦打上标记后,下一次无法访问到,但是下一次的状态还更优。
但是由于上下走最好,边权就相当于$0$.

$0-1BFS$用来解决:边权值为$0$或$1$,或者能够转化为这种边权值的最短路问题,时间复杂度为$O(E+V)$.

$0-1BFS$,从队列$front$中去除点$u$,遍历$u$的所有边,如果当前边可以进行$relax$操作,则$relax$,然后判断$level$,若$level$相同,放到队列的$front$,否则,放到$back$,队列采用双端队列$deque$。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 2e3 + 10;
const int mod = 1e9 + 7;
int dx[4] = {-1, +1, 0, 0}, dy[4] = {0, 0, -1, +1};
struct pd
{
int x, y, l, r;
};
char s[N][N];
int vis[N][N];
int n, m, r, c, x, y, ans;
int main()
{
scanf("%d%d%d%d%d%d", &n, &m, &r, &c, &x, &y);
for (int i = 1; i <= n; i++)
scanf("%s", s[i] + 1);
deque<pd> q;
q.push_back((pd){r, c, x, y});
vis[r][c] = 1;
while (!q.empty())
{
pd p = q.front();
q.pop_front();
if (p.l < 0 || p.r < 0)
continue;

s[p.x][p.y] = '+';
ans++;
for (int i = 0; i < 4; i++)
{
int xx = p.x + dx[i];
int yy = p.y + dy[i];
if (xx < 1 || xx > n || yy < 1 || yy > m || vis[xx][yy] || s[xx][yy] == '*')
continue;
vis[xx][yy] = 1;
if (i == 1 || i == 0)
q.push_front((pd){xx, yy, p.l, p.r});
else if (i == 2)
q.push_back((pd){xx, yy, p.l - 1, p.r});

else
q.push_back((pd){xx, yy, p.l, p.r - 1});
}
}
cout << ans << endl;
}