题解:CF1933F Turtle Mission: Robot and the Earthquake
题目大意
给你一张地图,机器人在左上角,目标在右下角,地图中有一些石头,每一个单位时间石头向上移动一格。机器人可以往上、下、右三个方向移动,求机器人走到终点的最短时间。
思路
石头肯定不能像题目描述一样动的。
可以考虑让石头不动,机器人相对石头运动。
设机器人当前的位置是 \((i, j)\)。
-
上:\((i, j)\).
-
下:\((i + 2, j)\)
-
右:\((i + 1, j + 1)\)
由于向上走相当于不动,所以只用考虑向下走和向右走。
然后宽搜就可以了。
代码
#include <bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define ll __int128
#define ldb long double
#define db double
#define bl bool
#define endl '\n'
#define PII pair<int, int>
#define PIII pair<int, PII>
#define p_q priority_queue
#define n_m unordered_map
#define il inline
#define re register
#define ve vector
#define bs bitset
#define m_p make_pair
using namespace std;
namespace OI {
template <typename T>
il T read() {
T x = 0, f = 1;
int ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
template <typename TE>
il void write(TE x) {
if (x < 0) {
x = -x;
putchar('-');
}
TE sta[35];
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top) putchar(sta[--top] + '0');
}
il string read_with_string() {
string s = "";
char ch = getchar();
while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
s += ch;
ch = getchar();
}
return s;
}
il void write_with_string(string s) {
for (int i = 0; i < s.size(); i++) putchar(s[i]);
}
}
using namespace OI;
//#define fre 1
//#define IOS 1
#define multitest 1
const int N = 1e3 + 10;
const int M = 4e5 + 10;
const int inf = 1e12;
int n, m, a[N][N];
bl vis[N][N];
int dp[N][N];
queue<PII> q;
int ans = inf;
il void Solve() {
ans = inf;
n = read<int>(), m = read<int>();
for (re int i = 0; i < n; i++)
for (re int j = 0; j < m; j++) {
a[i][j] = read<int>();
vis[i][j] = 0;
dp[i][j] = inf;
}
q.push(m_p(0, 0));
vis[0][0] = 1;
dp[0][0] = 0;
while (!q.empty()) {
PII t = q.front();
q.pop();
int x = t.first;
int y = t.second;
if (y == m - 1) {
int now = (n + dp[x][y] - 1) % n;
ans = min(ans, min((now - x + n) % n, (x - now + n) % n) + dp[x][y]);
continue;
}
int i, j;
i = (x + 2) % n;
if (a[(x + 1) % n][y] == 0 && a[i][y] == 0 && !vis[i][y]) {
q.push(m_p(i, y));
dp[i][y] = min(dp[i][y], dp[x][y] + 1);
vis[i][y] = 1;
}
i = (x + 1) % n, j = (y + 1) % m;
if (a[i][j] == 0 && !vis[i][j]) {
q.push(m_p(i, j));
dp[i][j] = min(dp[i][j], dp[x][y] + 1);
vis[i][j] = 1;
}
}
cout << (ans == inf ? -1 : ans) << endl;
}
signed main() {
int T;
#ifdef IOS
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#endif
#ifdef fre
freopen(".in", "r", stdin);
freopen(".ans", "w", stdout);
#endif
#ifdef multitest
cin >> T;
#else
T = 1;
#endif
while (T--) Solve();
return 0;
}
/*
*/
注意
一定要在更新队列元素的时候把当前移动到的点标记,这样可以避免一些坐标的重复计算,不然第 \(9\) 个点会 TLE
。