U254385 秘密通道(10.16&portal)题解
__newbie__ · · 个人记录
前言
地图转最短路模型。
题意
有一张
主角可以向上下左右移动一步(花费
求主角从终点到终点的最短时间。
基本思路
由于
- 搜索遍历
- 连边建图,转化为最短路问题
本题应考虑方案
详细思路
开通道的目的是什么?肯定是为了快速传送啊。如果开通道更加慢了,还不如不开。。。
要想比较二者之间的优劣,必定要将其量化。令到达传送目的地的时间为
既然有了量化指标,能够比较出路径之间的优劣。我们发现最短路正好需要这些特性,考虑对地图建图。
- 在相邻的两块空地之间建一条长度为
1 边 - 在可以传送的点之间建一条长为
f_{i,j} 的边
加边的过程可以在
完整代码
#include <bits/stdc++.h>
using namespace std;
const int N = 505, inf = 25000;
struct L{
int x, y, l;
bool operator<(const L &_l) const { return l > _l.l; }
};
struct E{
vector<L> e;
int d = inf;
} e[N * N];
int n, m, t, bx, by, ex, ey, ans = inf;
int dir[5][2] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};
int vis[N][N], f[N][N];
char mp[N][N];
priority_queue<L> que;
int p(int x, int y) {
return (x - 1) * m + y;
}
void Dijkstra() {
for (que.push({bx, by, 0}); !que.empty(); ) {
L h = que.top();
que.pop();
if (h.l < e[p(h.x, h.y)].d) {
e[p(h.x, h.y)].d = h.l;
for (int i = 0; i < 4; i++) {
int rx = h.x, ry = h.y, nx = rx + dir[i][0], ny = ry + dir[i][1];
if (mp[nx][ny] != '#' && nx >= 1 && ny >= 1 && nx <= n && ny <= m) {
que.push({nx, ny, h.l + 1});
for ( ; mp[rx + dir[i][0]][ry + dir[i][1]] != '#'; rx += dir[i][0], ry += dir[i][1]) {
}
que.push({rx, ry, h.l + f[h.x][h.y]});
}
}
}
}
}
void S(int sx, int sy, int x, int y, int step) {
if (step >= f[sx][sy] || vis[x][y] || x < 1 || y < 1 || x > n || y > m) {
return;
}
if (mp[x][y] == '#') {
f[sx][sy] = step;
return;
}
vis[x][y] = 1;
for (int i = 0; i < 4; i++) {
S(sx, sy, x + dir[i][0], y + dir[i][1], step + 1);
}
vis[x][y] = 0;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> mp[i][j];
f[i][j] = e[p(i, j)].d = inf;
if (mp[i][j] == 'C') {
bx = i, by = j;
} else if (mp[i][j] == 'F') {
ex = i, ey = j;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mp[i][j] != '#') {
S(i, j, i, j, 0);
}
}
}
Dijkstra();
if (e[p(ex, ey)].d == inf) {
cout << "nemoguce";
} else {
cout << e[p(ex, ey)].d;
}
return 0;
}
总结
- 地图类问题难想的,特别是数据范围大的——一定要多思考最短路