小蓝有一天误入了一个混境之地。他拿到了一张地图,并从中获取到以下信息:
#
表示不可通过的墙壁,.
表示可以走的路,V
表示圣泉。好消息是:他可以通过圣泉恢复体力。坏消息是:小蓝仅剩下 E E E 点能量,能量值不可小于 0。每行走一次消耗一点能量,耗时一分钟,在圣泉处每一分钟可以恢复一点体力,无上限。
小蓝想知道他能否逃离这个混境之地,如果可以逃离这里,则输入所需要的最少时间,反之输出 No
。
#
表示不可通过的墙壁,.
表示普通的道路,V
表示圣泉。输出数据共一行:
No
。5 5
1 1 5 5
...#.
..#..
#....
V..#.
...#.
5
19
从 (1, 1)
到 (5, 5)
的一条可行道路为:(1, 1) → (1, 2) → (2, 2) → (3, 2) → (4, 2) → (4, 1)
休息七个单位时间后 → (4, 2) → (4, 3) → (3, 3) → (3, 4) → (3, 5) → (4, 5) → (5, 5)
。
5 5
1 1 5 5
...#.
..#..
#....
V..##
...#.
200
No
不存在一条合法路径从起点到终点。
对于所有测试样例:
数据保证起点和终点一定为普通道路。
为了高效地解决这个问题,我们可以使用广度优先搜索(BFS)来计算从起点到每个点的距离以及从终点到每个点的距离。然后,我们检查是否有足够的能量到达终点或经过圣泉恢复能量后到达终点。
#include
using namespace std;
using ll = long long;
const int N = 1e3 + 9;
const int MAX_INF = 0x3f3f3f3f;
char mp[N][N];
int n, m, a, b, c, d, E;
int pre[N][N], nex[N][N]; // 分别存储从起点和终点出发到每个点的最短距离
int dx[] = {1, 0, -1, 0}; // 方向数组
int dy[] = {0, 1, 0, -1};
vector<pair<int, int>> v; // 存储所有圣泉的位置
struct node {
int cx, cy, d; // 当前坐标和距离
};
bool vis[N][N];
// 广度优先搜索计算最短路径
void bfs(int x, int y, int dis[N][N]){
queue<node> q;
q.push({x, y, 0});
dis[x][y] = 0;
while(!q.empty()){
node cq = q.front(); q.pop();
dis[cq.cx][cq.cy] = cq.d;
for(int i = 0; i < 4; i++){
int nx = cq.cx + dx[i], ny = cq.cy + dy[i];
if(nx < 1 || ny < 1 || nx > n || ny > m) continue;
if(mp[nx][ny] == '#') continue;
if(!vis[nx][ny]){
vis[nx][ny] = true;
q.push({nx, ny, cq.d + 1});
}
}
}
}
int main(){
ios::sync_with_stdio(0),
cin.tie(0), cout.tie(0);
cin >> n >> m;
cin >> a >> b >> c >> d;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
cin >> mp[i][j];
if(mp[i][j] == 'V'){
v.push_back({i, j}); // 记录所有圣泉的位置
}
}
cin >> E;
memset(pre, 0x3f, sizeof pre); // 初始化距离数组
memset(nex, 0x3f, sizeof nex);
vis[a][b] = true;
bfs(a, b, pre); // 从起点开始BFS
memset(vis, false, sizeof vis);
vis[c][d] = true;
bfs(c, d, nex); // 从终点开始BFS
int ans = MAX_INF;
// 如果可以直接到达终点
if(E >= pre[c][d]){
if(pre[c][d] == MAX_INF) cout << "No" << '\n';
else cout << pre[c][d] << '\n';
return 0;
}
// 检查是否可以通过圣泉恢复能量后到达终点
for(const auto &p : v){
int x = p.first, y = p.second;
if(pre[x][y] <= E){
ans = min(ans, pre[x][y] + nex[x][y]);
}
}
if(ans != 0x3f3f3f3f){
cout << E + (ans - E) * 2 << '\n'; // 计算总时间
} else {
cout << "No" << '\n';
}
return 0;
}
此代码通过两次广度优先搜索(BFS)分别计算从起点和终点出发到每个点的最短距离。首先检查是否可以直接到达终点,如果不能,则检查是否可以通过圣泉恢复能量后到达终点。这种方法能够有效地处理大规模数据,并确保在有限的时间内找到最优解。
此题的关键在计算起点和终点分别到每一个点的最短距离并预处理,可以轻易获取到如果要经过这个点时从起点到终点的最短距离, 在预处理时注意细节
小蓝有一天误入了一个混境之地。他拿到了一张地图,并从中获取到以下信息:
#
表示墙,无法通行,.
表示普通的道路,k
表示散落在地图中的钥匙。好消息是:地图中可能存在不止一把钥匙。坏消息是:地图中可能没有钥匙。小蓝可以往上下左右四个方向行走,每走一步耗时一分钟。
小蓝想知道他能否逃离这个混境之地,如果可以逃离这里,则输出最少需要消耗多少时间,反之输出 -1
。
#
表示墙,无法通行,.
表示普通的道路,k
表示散落在地图中的钥匙。输出数据共一行一个字符串:
-1
。5 5
1 1 5 5
....#
#.#..
k.#..
.#...
...#.
12
从 (1, 1)
到 (5, 5)
的最短道路为:
(1, 1) → (1, 2) → (2, 2) → (3, 2) → (3, 1)
拿到钥匙。(3, 1) → (4, 1) → (5, 1) → (5, 2) → (5, 3) → (4, 3) → (4, 4) → (4, 5) → (5, 5)
到达终点。5 5
1 1 5 5
....#
#.##.
k.#..
##...
...#.
-1
可以证明不存在一条路径可以从起点到达终点。
对于所有测试样例:
数据保证起点和终点一定为普通道路。
为了高效地解决这个问题,我们可以使用广度优先搜索(BFS)来计算从起点到每个点的距离以及从终点到每个点的距离。然后,我们检查是否存在一条路径可以通过至少一把钥匙并最终到达终点。
#include
using namespace std;
using ll = long long;
const int N = 1e3 + 9, MAX_INF = 0x3f3f3f3f;
char mp[N][N];
int n, m, a, b, c, d, pre[N][N], nex[N][N], dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
bool vis[N][N];
struct node {
int x, y, d; // 当前坐标和距离
};
// 广度优先搜索计算最短路径
void bfs(int x, int y, int dis[N][N]){
queue<node> q;
q.push({x, y, 0});
while(!q.empty()){
node cq = q.front(); q.pop();
vis[cq.x][cq.y] = true;
dis[cq.x][cq.y] = cq.d;
for(int i = 0; i < 4; i++){
int nx = cq.x + dx[i], ny = cq.y + dy[i];
if(nx < 1 || ny < 1 || nx > n || ny > m) continue;
if(mp[nx][ny] == '#') continue;
if(!vis[nx][ny]){
vis[nx][ny] = true;
q.push({nx, ny, cq.d + 1});
}
}
}
}
vector<pair<int, int>> v; // 存储所有钥匙的位置
int main(){
ios::sync_with_stdio(0),
cin.tie(0), cout.tie(0);
cin >> n >> m;
cin >> a >> b >> c >> d;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
cin >> mp[i][j];
if(mp[i][j] == 'k') v.push_back({i, j}); // 记录所有钥匙的位置
}
memset(pre, 0x3f, sizeof pre); // 初始化距离数组
memset(nex, 0x3f, sizeof nex);
memset(vis, false, sizeof vis);
bfs(a, b, pre); // 从起点开始BFS
memset(vis, false, sizeof vis);
bfs(c, d, nex); // 从终点开始BFS
if(v.size() == 0){
cout << -1 << '\n';
return 0;
}
int ans = MAX_INF;
// 检查是否可以通过某个钥匙位置到达终点
for(const auto &p : v){
int x = p.first, y = p.second;
if(pre[x][y] == MAX_INF || nex[x][y] == MAX_INF) continue;
ans = min(ans, pre[x][y] + nex[x][y]);
}
if(ans == MAX_INF){
cout << -1 << '\n';
} else {
cout << ans << '\n';
}
return 0;
}
此代码通过两次广度优先搜索(BFS)分别计算从起点和终点出发到每个点的最短距离。首先记录所有钥匙的位置,然后检查是否有路径可以通过至少一把钥匙并最终到达终点。这种方法能够有效地处理大规模数据,并确保在有限的时间内找到最优解。如果没有钥匙或无法通过任何钥匙到达终点,则输出 -1
。