思路:
普通的dfs和bfs需要打vis标记,而在这题中标记不好处理,因为可能会遇到先到一个地方加满hp再原路返回的情况。
这里我们用f数组记录(i, j)位置上的最大hp,因为到达一个点(x, y)时的hp较少的话走出来的结果不会比f[x][y]走出来的结果更优,因此我们根据这一性质进行剪枝,而不使用vis标记。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PI;
const int N = 60;
const int dir[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };
struct Node {
int x, y, hp, step;
};
int n, m, mp[N][N];
PI st;
int f[N][N]; //f[i][j] 表示 (i, j)位置上的最大hp
int ans = -1;
void bfs() {
queue<Node> q;
q.push({st.first, st.second, 6, 0});
while (!q.empty()) {
Node now = q.front(); q.pop();
if (now.x < 1 || now.x > n || now.y < 1 || now.y > m) //越界
continue;
if (!now.hp || mp[now.x][now.y] == 0) //hp为0/障碍物
continue;
if (now.hp <= f[now.x][now.y]) //最优性剪枝
continue;
f[now.x][now.y] = now.hp;
if (mp[now.x][now.y] == 3) {
ans = now.step;
return;
}
if (mp[now.x][now.y] == 4) {
now.hp = 6;
}
for (int i = 0; i < 4; i++) {
int dx = now.x + dir[i][0], dy = now.y + dir[i][1];
q.push({dx, dy, now.hp - 1, now.step + 1});
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
cin >> mp[i][j];
if (mp[i][j] == 2) st.first = i, st.second = j;
}
bfs();
cout << ans << endl;
return 0;
}
/*
9 9
2 0 1 1 4 0 1 1 4
1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1
1 0 4 0 1 0 4 0 1
1 0 1 0 1 0 1 0 1
4 0 1 0 4 0 1 0 3
1 0 1 0 1 0 1 0 0
1 0 1 0 1 0 1 0 0
1 1 4 0 1 1 4 0 0
//ans = 45
9 9
2 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4 3
//ans = 16
test 11
7 6
2 0 0 0 0 0
1 0 0 0 0 0
1 1 4 0 0 0
1 0 0 0 0 0
1 1 1 1 1 3
4 0 1 0 4 0
0 0 4 0 0 0
//ans = 15
*/