P9351 [JOI 2023 Final] Maze 题解
Description
给定一张 .
可以走,而 #
不能走。一次操作可以将 .
,给定起点和终点,求最少需要几次操作使得起点和终点连通(只能上下左右移动)。
Solution
先考虑怎么暴力求出答案。
假设当前从起点走到了
或者花费
建图跑 01bfs 可以得到一个
由于算法慢在二操作的边数过多,所以考虑把二操作的长距离走法优化成多次走相邻格子的过程。
因为
于是把步数作为第一关键字,走的八联通步数看作第二关键字跑最短路即可。
dijkstra 直接做可以做到
时间复杂度:
Code
#include <bits/stdc++.h> // #define int int64_t const int kMaxT = 6e6 + 5, kMaxN = 3e3 + 5; const int kD4[][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; const int kD8[][2] = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}, {0, 1}, {0, -1}, {1, 0}, {-1, 0}}; int n, m, k; int sx, sy, tx, ty; std::vector<int> G[kMaxT]; std::string s[kMaxN]; void dijkstra() { std::vector<std::vector<std::pair<int, int>>> dis(n + 1, std::vector<std::pair<int, int>>(m + 1)); std::vector<std::vector<bool>> vis(n + 1, std::vector<bool>(m + 1)); std::priority_queue<std::tuple<int, int, int, int>> q; for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) dis[i][j] = {1e9, 1e9}; dis[sx][sy] = {0, k - 1}; q.emplace(0, -(k - 1), sx, sy); for (; !q.empty();) { auto [d, w, x, y] = q.top(); q.pop(); if (vis[x][y]) continue; vis[x][y] = 1; for (auto [dx, dy] : kD4) { int tx = x + dx, ty = y + dy; if (tx < 1 || tx > n || ty < 1 || ty > m) continue; if (s[tx][ty] == '.') { std::pair<int, int> p = {dis[x][y].first, k - 1}; if (dis[tx][ty] > p) { dis[tx][ty] = p; q.emplace(-p.first, -p.second, tx, ty); } } std::pair<int, int> p = {dis[x][y].first + 1, 0}; if (dis[tx][ty] > p) { dis[tx][ty] = p; q.emplace(-p.first, -p.second, tx, ty); } } if (dis[x][y].second < k - 1) { for (auto [dx, dy] : kD8) { int tx = x + dx, ty = y + dy; if (tx < 1 || tx > n || ty < 1 || ty > m) continue; std::pair<int, int> p = {dis[x][y].first, dis[x][y].second + 1}; if (dis[tx][ty] > p) { dis[tx][ty] = p; q.emplace(-p.first, -p.second, tx, ty); } } } } std::cout << dis[tx][ty].first << '\n'; } void dickdreamer() { std::cin >> n >> m >> k >> sx >> sy >> tx >> ty; for (int i = 1; i <= n; ++i) { std::cin >> s[i]; s[i] = " " + s[i]; } dijkstra(); } int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; // std::cin >> T; while (T--) dickdreamer(); // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步