Hướng dẫn giải của Robot Cleaner 2
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Ta xét phiên bản một chiều của bài toán: có ~n~ ô nằm trên một hàng. Robot bắt đầu tại ô thứ ~x~, còn tất cả các ô khác đều đang bẩn. Mỗi giây, robot lau ô mà nó đang đứng. Ban đầu, robot di chuyển sang phải, mỗi giây đi sang ô kế tiếp. Nếu phía trước không còn ô nào để đi tiếp, robot sẽ quay đầu. Hỏi sau bao lâu thì robot lau sạch toàn bộ các ô?
Có hai trường hợp cần xét:
Nếu ~x = 1~, đáp án là ~n - 1~. Robot bắt đầu từ ô ngoài cùng bên trái, nên chỉ cần đi thẳng sang phải đến cuối hàng và lau sạch mọi ô trên đường đi.
Nếu ~x > 1~, để lau được ô thứ nhất, robot bắt buộc phải đi đến ô cuối cùng trước, rồi mới quay lại ô thứ nhất. Robot mất ~n - x~ giây để đi từ ô ~x~ đến ô ~n~, sau đó mất thêm ~n - 1~ giây để đi từ ô ~n~ về ô ~1~. Vì vậy, đáp án trong trường hợp này là $$(n - x) + (n - 1) = 2n - x - 1.$$
Quay lại bài toán ban đầu, ta có thể tách chuyển động của robot thành hai bài toán một chiều độc lập: một bài toán trên các hàng và một bài toán trên các cột. Nói cách khác, ta chiếu đường đi của robot lên trục dọc và trục ngang, rồi xét hai trục này riêng biệt.
Mỗi khi robot đứng tại ô ~(r, c)~, nó lau toàn bộ hàng ~r~ và toàn bộ cột ~c~. Do đó, một ô bất kỳ ~(i, j)~ sẽ được lau nếu robot đã từng đi qua hàng ~i~ hoặc từng đi qua cột ~j~.
Vì vậy, sàn được lau sạch hoàn toàn khi robot đã đi qua tất cả các hàng, hoặc đã đi qua tất cả các cột. Ta chỉ cần giải bài toán một chiều cho hàng và cho cột, rồi lấy giá trị nhỏ hơn trong hai kết quả.
#include <bits/stdc++.h> using namespace std; int solve_1d(int n, int pos) { return pos == 1 ? n - 1 : n - 1 + n - pos; } int solve_2d(int n, int m, int r, int c) { return min(solve_1d(n, r), solve_1d(m, c)); } int main() { cin.tie(0)->sync_with_stdio(0); int ntest; cin >> ntest; while (ntest--) { int n, m, rb, cb; cin >> n >> m >> rb >> cb; cout << solve_2d(n, m, rb, cb) << '\n'; } return 0; }
Bình luận