题解: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;
}
/*

*/

AC 记录

注意

一定要在更新队列元素的时候把当前移动到的点标记,这样可以避免一些坐标的重复计算,不然第 \(9\) 个点会 TLE

posted @ 2024-10-25 11:03  zla_2012  阅读(4)  评论(0编辑  收藏  举报