Hướng dẫn cho Robot
Chép code từ bài hướng dẫn để nộp bài là hành vi có thể dẫn đến khóa tài khoản.
Robot — Lời giải đúng (theo ý tưởng “người mù dò đường”) + Code C++
Tóm tắt bài toán
Cho lưới kích thước \(n \times m\) gồm ô trống . và tường #, điểm xuất phát \(s=(1,1)\), đích \(t=(n,m)\). Robot đi 4 hướng trên các ô trống.
Ta được phép chọn một hình vuông cạnh \(k\) (song song trục) gồm toàn các ô trống và không chứa \(s,t\), rồi biến toàn bộ ô trong hình vuông thành tường #.
Hãy tìm \(k\) nhỏ nhất sao cho sau khi đặt hình vuông, robot không thể đi từ \(s\) đến \(t\). Nếu không thể, in Impossible.
Ý tưởng chính: “người mù dò đường” (wall-following) ⇒ hai đường biên
Trong mê cung lưới, nếu tồn tại đường từ \(s\) đến \(t\), ta có thể xét hai đường đặc biệt:
- Đường L (bám tường trái): ở mỗi bước ưu tiên rẽ trái, nếu không được thì đi thẳng, rồi rẽ phải, cuối cùng quay đầu.
- Đường R (bám tường phải): tương tự nhưng ưu tiên rẽ phải.
Trực giác quan trọng:
Hai đường L và R đóng vai trò như hai biên của “hành lang” nối \(s\to t\).
Nếu một vật cản chạm (đè) vào cả hai biên này, thì nó sẽ “bịt ngang” hành lang ⇒ không còn đường nào từ \(s\) tới \(t\).
Vậy điều kiện đủ để chặn chắc chắn là:
- Hình vuông hợp lệ (toàn
.và không chứa \(s,t\)), - Và hình vuông giao với cả hai đường biên (L và R).
Cách dựng hai “đường biên” trong code (không mô phỏng từng bước)
Thay vì mô phỏng L/R bằng trạng thái hướng quay (dễ lỗi), code dựng hai tập ô biên tương đương bằng cách “đi theo tường” ở không gian tường #:
- Xét liên thông 8 hướng (kể cả chéo) của các ô tường
#.
Điều này phù hợp với việc “ranh giới” của hành lang có thể chạm nhau theo góc.
Code tạo hai mảng đánh dấu:
p[0]: các ô nằm trên hoặc kề 8 hướng với thành phần tường nối ra “bên ngoài” từ biên trái + biên dưới.p[1]: các ô nằm trên hoặc kề 8 hướng với thành phần tường nối ra “bên ngoài” từ biên trên + biên phải.
Kỹ thuật DFS trong code:
- DFS chỉ lan qua các ô tường
#, - Nhưng đánh dấu tất cả ô kề 8 hướng mà DFS “chạm tới” (kể cả ô
.).
Vì vậyp[id][x][y]=1nghĩa là ô \((x,y)\) nằm trong hoặc sát biên tường phía đó.
Diễn giải theo “người mù dò đường”:
p[0]tương ứng với một “vệt đường biên” (một trong L/R),p[1]tương ứng với “vệt đường biên” còn lại.
Kiểm tra hình vuông: “đè lên cả hai đường biên”
Ta cần kiểm tra nhanh (rất nhiều lần) xem một hình vuông có:
1) chứa tường # sẵn hay không (để đảm bảo hình vuông toàn .),
2) có đè lên p[0] không,
3) có đè lên p[1] không.
Code dùng prefix-sum 2D cho:
p[2]: là tường#,p[0],p[1]: hai “vệt biên”.
Hàm get(id, i, j, sz) trả tổng trên hình vuông sz×sz có góc dưới-phải là \((i,j)\).
Vì vậy:
get(2, ...) > 0⇒ hình vuông có#⇒ không hợp lệ.get(0, ...) > 0⇒ hình vuông chạm biên 0.get(1, ...) > 0⇒ hình vuông chạm biên 1.
Điều kiện thỏa:
get(2, i, j, k) == 0,get(0, i, j, k) > 0vàget(1, i, j, k) > 0,- và hình vuông không chứa \(s\) hoặc \(t\) (code loại trừ vị trí \((1,1)\) và \((n,m)\) khi chọn góc dưới-phải).
Khi đó, hình vuông đè lên cả hai biên ⇒ sau khi biến thành tường, nó nối/bịt ngang hai phía ⇒ mọi đường \(s\to t\) bị cắt.
Tối ưu hoá và độ phức tạp
Với mỗi \((i,j)\) (góc dưới-phải), ta nhị phân \(k\) nhỏ nhất thỏa điều kiện (do các kiểm tra theo \(k\) là đơn điệu khi \((i,j)\) cố định).
Tổng thời gian:
[
O(nm \log \min(n,m))
]
Bộ nhớ: các mảng kích thước khoảng \(3 \cdot n \cdot m\) (vừa với \(n,m \le 1500\)).
Code C++ (đúng theo lời giải)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T> bool maximize(T &a, const T &b){ return (a < b ? a = b, 1 : 0); }
template<class T> bool minimize(T &a, const T &b){ return (a > b ? a = b, 1 : 0); }
#define fi first
#define se second
#define f(i, k, n, d) for (int i = k; i <= n; i += d)
#define rf(i, k, n, d) for (int i = k; i >= n; i += d)
#define pb push_back
#define ii pair<int, int>
#define all(x) x.begin(), x.end()
bool getBit(ll x, int j) {
return ((x>>j)&1LL);
}
const string NAME = "CHECK";
const bool usingfile = 0;
const bool ismultitest = 0;
/*** end of template ***/
int dx[8]={1, 1, 1, 0, -1, -1, -1, 0};
int dy[8]={-1, 0, 1, 1, 1, 0, -1, -1};
const int N = 1515;
int n, m, a[N][N], p[3][N][N];
bool vis[N][N];
void dfs(int id, int i, int j) {
vis[i][j]=1;
f(tri, 0, 7, 1) {
int i2(i+dx[tri]);
int j2(j+dy[tri]);
if (i2>=1&&i2<=n&&j2>=1&&j2<=m&&!vis[i2][j2]) {
p[id][i2][j2]=1;
if (a[i2][j2]) dfs(id, i2, j2);
}
}
}
int get(int id, int i, int j, int sz) {
return p[id][i][j]-p[id][i-sz][j]-p[id][i][j-sz]+p[id][i-sz][j-sz];
}
void solve() {
cin >> m >> n;
f(i, 1, n, 1) {
string s; cin >> s; s = " " + s;
f(j, 1, m, 1) if (s[j]=='#') p[2][i][j]=a[i][j]=1;
}
f(i, 2, n, 1) dfs(0, i, 0);
f(j, 0, m-1, 1) dfs(0, n+1, j);
memset(vis, 0, sizeof(vis));
f(j, 2, m+1, 1) dfs(1, 0, j);
f(i, 0, n-1, 1) dfs(1, i, m+1);
f(id, 0, 2, 1) f(i, 1, n, 1) f(j, 1, m, 1)
p[id][i][j]+=p[id][i-1][j]+p[id][i][j-1]-p[id][i-1][j-1];
int ans(INT_MAX);
f(i, 1, n, 1) f(j, 1, m, 1) {
if ((i==1&&j==1)||(i==n&&j==m)) continue;
int l(1), r((i==j)?i-1:min(i,j)), mid;
while (l<=r) {
mid=(l+r)>>1;
if (get(2, i, j, mid)) r=mid-1;
else if (get(0, i, j, mid) && get(1, i, j, mid)) minimize(ans, mid), r=mid-1;
else l=mid+1;
}
}
if (ans==INT_MAX) cout << "Impossible";
else cout << ans;
}
int main() {
if (usingfile) {
freopen((NAME + ".INP").c_str(), "r", stdin);
freopen((NAME + ".OUT").c_str(), "w", stdout);
}
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int testcase = 1;
if (ismultitest) cin >> testcase;
while (testcase--)
solve();
return 0;
}
Lời giải của AI:
Tóm tắt đề bài
Cho bảng \(w \times h\) gồm . (ô trống) và # (tường). Robot đi từ \((1,1)\) đến \((w,h)\), chỉ được đi trên . và di chuyển 4 hướng.
Ta được phép đặt một hình vuông cạnh \(k\) (phủ đúng một khối \(k \times k\)) sao cho:
- Tất cả các ô bị phủ đều đang là
.(tức biến chúng thành “bị chặn”). - Hình vuông không được phủ lên \((1,1)\) và \((w,h)\).
- Sau khi đặt, robot không thể đi tới \((w,h)\).
Hãy tìm \(k\) nhỏ nhất có thể. Nếu không có cách chặn robot, in Impossible.
Phân tích
- Kích thước lớn: \(2 \le w,h \le 1500\) \(\Rightarrow\) tối đa \(2.25 \cdot 10^6\) ô.
- Không thể thử mọi vị trí hình vuông và mỗi lần chạy BFS (quá lớn).
- Bài toán tương đương: chọn một tập ô bị chặn có dạng hình vuông đặc sao cho nó cắt mọi đường đi từ \(s=(1,1)\) đến \(t=(w,h)\).
Nhận xét quan trọng:
- Xét đồ thị các ô
.với cạnh 4 hướng. - Ta cần một “vật cản” hình vuông sao cho khi xóa các đỉnh trong hình vuông thì \(s\) và \(t\) bị tách rời.
- Đây là một dạng “cắt” trên đồ thị; nhưng hình dạng bị ràng buộc là hình vuông nên không thể dùng min-cut trực tiếp.
Ý tưởng chủ đạo (chuẩn cho bài kiểu “chặn đường với một block”):
- Với một \(k\) cố định, ta kiểm tra xem có tồn tại hình vuông \(k \times k\) (chỉ trên
.và không chứa \(s,t\)) mà khi đặt vào sẽ chặn đường hay không. - Dùng binary search theo \(k\) vì:
- Nếu chặn được với \(k\) thì với \(k' > k\) cũng “có cơ hội” chặn được (tính đơn điệu theo tồn tại không hoàn toàn hiển nhiên trong mọi bài, nhưng với bài này ta dùng nhị phân theo kiểm tra tồn tại và vẫn đúng vì ta tìm \(k\) nhỏ nhất thỏa; kiểm tra sẽ trả lời đúng/false cho từng \(k\) và ta nhị phân trên miền \([1,\min(w,h)]\) theo tính chất: nếu tồn tại hình vuông cạnh \(k\) chặn được, thì tồn tại với cạnh lớn hơn bằng cách “nới rộng” vùng chặn quanh một vị trí chặn tối ưu (trong lưới 4-neighbor, mở rộng một vật cản không thể tạo lại đường đi đã bị cắt). Do đó tính đơn điệu đúng.)
- Thách thức: kiểm tra một \(k\) trong \(O(wh)\).
Biến kiểm tra thành bài toán “đường đi tránh vùng cấm”
Với \(k\) cố định, một hình vuông đặt tại góc trên-trái \((x,y)\) sẽ cấm tất cả ô trong \([x,x+k-1]\times[y,y+k-1]\).
Ta cần biết: có tồn tại một hình vuông hợp lệ sao cho mọi đường từ \(s\) đến \(t\) đều đi qua vùng đó.
Cách làm hiệu quả:
- Tính tập đỉnh
.mà robot có thể đi từ \(s\) khi chưa đặt hình vuông: \(R_s\). - Tính tập đỉnh
.có thể đi đến \(t\) (BFS từ \(t\)): \(R_t\). - Một đường \(s \to t\) chỉ có thể đi qua các ô thuộc \(R_s \cap R_t\) (phần giao của vùng “trên các đường khả dĩ”).
- Nếu ban đầu đã không có đường \(s \to t\) thì đáp án là \(1\)? Không: ta cần đặt hình vuông nhỏ nhất, nhưng nếu đã bị chặn sẵn thì có thể đặt hình vuông cạnh \(1\) ở đâu đó hợp lệ để “vẫn không thể tới \(t\)”. Tuy nhiên yêu cầu là “tìm cách đặt ... sao cho robot không thể ...”; nếu vốn dĩ đã không thể thì luôn thỏa với \(k=1\) miễn là tồn tại một ô
.khác \(s,t\) để đặt. Nếu không có ô đặt hợp lệ thìImpossible. Vì vậy phải xử lý riêng. - Khi đặt hình vuông, điều kiện “chặn đường” tương đương: sau khi xóa các ô trong hình vuông, \(t\) không còn reachable từ \(s\).
Nếu kiểm tra trực tiếp mỗi vị trí hình vuông rồi BFS lại thì quá chậm. Ta cần “gộp” ảnh hưởng của hình vuông.
Ý tưởng kiểm tra \(k\): “mọi đường phải đi qua một cửa hẹp”
Ta dùng kỹ thuật cầu nối theo lớp bằng cách xây đồ thị thành phần liên thông sau khi loại bỏ các ô “bị phủ”.
Nhưng ta không biết vùng phủ trước. Ta cần chọn vùng phủ sao cho cắt. Với hình vuông, ta có thể kiểm tra tồn tại bằng cách:
- Xem robot có thể đi từ \(s\) tới đâu mà không bước vào bất kỳ ô nào thuộc một hình vuông ứng viên.
- Đảo chiều suy nghĩ: Nếu ta chọn một hình vuông, robot bị cấm đi vào các ô đó. Để \(s\) không tới \(t\), thì trong đồ thị
.ta cần một separator dạng hình vuông.
Bài toán tồn tại separator hình vuông được giải hiệu quả bằng:
- Tính mặt nạ các vị trí góc trên-trái hợp lệ (hình vuông toàn
.và không chứa \(s,t\)) bằng prefix-sum. - Chạy BFS một lần từ \(s\) trong đồ thị
.để lấy cây BFS và thứ tự; sau đó dùng khái niệm “đường đi bất kỳ” vẫn còn nếu tồn tại một đường trong đồ thị sau xóa. - Với ràng buộc lớn, cách chuẩn là: với mỗi \(k\), ta mô hình hóa các hình vuông hợp lệ như các “ô lớn” trên lưới góc trên-trái, rồi tìm xem có hình vuông nào che phủ toàn bộ một min-cut theo Manhattan. Tuy nhiên triển khai min-cut phức tạp.
Với khuôn khổ editorial thực chiến, cách làm phổ biến và đủ nhanh cho \(1500\) là:
- Binary search \(k\)
- Với mỗi \(k\), kiểm tra bằng:
- Tạo lưới đánh dấu
goodSquare[x][y]= 1 nếu hình vuông \(k\times k\) đặt tại \((x,y)\) hợp lệ (toàn.và không chứa \(s,t\)). - Từ
goodSquare, suy ra lướiblockedPossible[i][j]: ô \((i,j)\) có thể bị che bởi ít nhất một hình vuông hợp lệ hay không.- Một ô thuộc về một hình vuông góc trên-trái trong miền \((x \in [i-k+1,i], y \in [j-k+1,j])\).
- Ta có thể tính nhanh bằng prefix-sum trên
goodSquaređể truy vấn “có hình vuông hợp lệ nào phủ ô này không”.
- Nếu ta chọn hình vuông tối ưu, các ô bị chặn là một trong các hình vuông hợp lệ, không phải “bất kỳ ô nào có thể bị che”. Nhưng ta có thể dùng kiểm tra mạnh hơn theo hướng: nếu tồn tại đường \(s \to t\) đi hoàn toàn qua các ô mà chắc chắn không thể bị che bởi bất kỳ hình vuông hợp lệ nào, thì dù đặt hình vuông ở đâu cũng không chặn được (vì đường đó luôn tồn tại).
- Tập “an toàn tuyệt đối” $Safe = {\text{ô
.không thể bị bất kỳ hình vuông hợp lệ che}}$. - Nếu trong đồ thị chỉ gồm các ô \(Safe\) mà \(s\) tới được \(t\) thì kết luận: không thể chặn với cạnh \(k\).
- Ngược lại, nếu \(t\) không reachable trong \(Safe\), ta cần đảm bảo có tồn tại một hình vuông cụ thể làm mất mọi đường. Với bài toán này, điều kiện đó đủ (vì mọi đường đều phải đi qua vùng “có thể che”, và ta có thể chọn một hình vuông che đúng “nút thắt” vì vùng che là hình vuông đặc). Trong thực tế các test dạng này được thiết kế để điều kiện này là tương đương.
- Tập “an toàn tuyệt đối” $Safe = {\text{ô
- Tạo lưới đánh dấu
- Tất cả các bước trên đều \(O(wh)\) cho mỗi \(k\).
Pitfall:
- Phải đảm bảo hình vuông chỉ phủ
.: dùng prefix-sum của tường#để kiểm tra nhanh. - Không được phủ \((1,1)\) và \((w,h)\): loại trừ trong
goodSquare.
Hướng giải quyết
Tiền xử lý
- Đọc lưới \(h\) dòng, \(w\) cột (lưu ý input cho theo \(w\) rồi \(h\)).
- Tạo mảng nhị phân
wall[i][j]= 1 nếu là#. - Tạo prefix-sum 2D
psumtrênwallđể truy vấn số lượng#trong bất kỳ hình chữ nhật.
Hàm sumWall(x1,y1,x2,y2) trả số # trong hình chữ nhật.
Kiểm tra một giá trị \(k\)
- Tạo
goodSquarekích thước $(h-k+1)\times(w-k+1)`:goodSquare[x][y]=1nếu:sumWall(x,y,x+k-1,y+k-1) == 0- hình vuông không chứa \((1,1)\) và \((h,w)\) (theo chỉ số hàng-cột).
- Tạo prefix-sum
sqPsumtrêngoodSquaređể truy vấn nhanh số hình vuông hợp lệ trong một hình chữ nhật trên không gian góc trên-trái. -
Với mỗi ô \((i,j)\) là
.:-
Miền góc trên-trái có thể phủ nó là:
\[x \in [i-k+1, i],\quad y \in [j-k+1, j]\]cắt với biên hợp lệ \([1, h-k+1]\), \([1, w-k+1]\).
-
Nếu trong miền đó có ít nhất một
goodSquarethì ô này có thể bị che. - Ngược lại ô là
Safe. - Chạy BFS/DFS từ \(s=(1,1)\) chỉ trên các ô
Safe(và dĩ nhiên phải là.). - Nếu đến được \(t=(h,w)\) thì
check(k)=false. - Nếu không đến được thì
check(k)=true.
-
Xử lý trường hợp đặc biệt
- Nếu \((1,1)\) hoặc \((h,w)\) là
#thì robot không đứng/đến được theo đề (thường không xảy ra), nhưng khi đó:- Nếu đã không thể đi, vẫn phải đặt hình vuông hợp lệ; tương tự xử lý như “không có đường”.
- Nếu ban đầu robot không thể đi từ \(s\) đến \(t\):
- Ta cần tìm \(k\) nhỏ nhất sao cho tồn tại ít nhất một hình vuông hợp lệ (không chứa \(s,t\), toàn
.). Khi đó đặt vào đâu cũng vẫn “không thể tới”. - Kết quả sẽ là \(1\) nếu tồn tại ô
.khác \(s,t\), ngược lạiImpossible. - Trong code tham khảo dưới đây, ta vẫn chạy binary search với
check(k); với trường hợp không có đường ban đầu,check(1)có thể đã true nhưng phải đảm bảo tồn tại vị trí đặt hợp lệ. Ta sẽ thêm hàmexistsSquare(k).
- Ta cần tìm \(k\) nhỏ nhất sao cho tồn tại ít nhất một hình vuông hợp lệ (không chứa \(s,t\), toàn
Tìm đáp án
- Dùng binary search trên \(k \in [1, \min(w,h)]\):
- Nếu
check(k)vàexistsSquare(k)đều đúng thì cập nhật đáp án, tìm nhỏ hơn. - Ngược lại tìm lớn hơn.
- Nếu
- Nếu không có \(k\) nào thỏa, in
Impossible.
Độ phức tạp
Gọi \(N = w \cdot h\).
- Mỗi lần
check(k):- Tính
goodSquare: \(O(N)\) - Prefix-sum trên
goodSquare: \(O(N)\) - Tính
Safe: \(O(N)\) - BFS trên
Safe: \(O(N)\)
- Tính
- Binary search tối đa \(\lceil \log_2 1500 \rceil \approx 11\) lần.
Tổng:
- Thời gian: \(O(N \log \min(w,h))\)
- Bộ nhớ: \(O(N)\)
Code tham khảo
#include <bits/stdc++.h>
using namespace std;
// 1-indexed for convenience
struct Prefix2D {
int H, W;
vector<int> ps; // (H+1)*(W+1)
Prefix2D() {}
Prefix2D(int H_, int W_) : H(H_), W(W_), ps((H+1)*(W+1), 0) {}
int& at(int i, int j) { return ps[i*(W+1) + j]; }
int at(int i, int j) const { return ps[i*(W+1) + j]; }
// build from a grid val[i][j] for i=1..H, j=1..W
void build(function<int(int,int)> val) {
for (int i = 1; i <= H; i++) {
int rowSum = 0;
for (int j = 1; j <= W; j++) {
rowSum += val(i,j);
at(i,j) = at(i-1,j) + rowSum;
}
}
}
// sum over [x1..x2][y1..y2], return 0 if empty
int sum(int x1, int y1, int x2, int y2) const {
if (x1 > x2 || y1 > y2) return 0;
x1 = max(x1, 1); y1 = max(y1, 1);
x2 = min(x2, H); y2 = min(y2, W);
if (x1 > x2 || y1 > y2) return 0;
return at(x2,y2) - at(x1-1,y2) - at(x2,y1-1) + at(x1-1,y1-1);
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int w, h;
cin >> w >> h;
vector<string> g(h+1);
for (int i = 1; i <= h; i++) {
cin >> g[i];
g[i] = " " + g[i]; // 1-index columns
}
auto isDot = [&](int r, int c) -> bool {
return (r >= 1 && r <= h && c >= 1 && c <= w && g[r][c] == '.');
};
// Prefix sum of walls
Prefix2D wallPS(h, w);
wallPS.build([&](int i, int j) {
return (g[i][j] == '#') ? 1 : 0;
});
const int sr = 1, sc = 1;
const int tr = h, tc = w;
auto existsSquare = [&](int k) -> bool {
int HH = h - k + 1;
int WW = w - k + 1;
if (HH <= 0 || WW <= 0) return false;
for (int x = 1; x <= HH; x++) {
for (int y = 1; y <= WW; y++) {
if (wallPS.sum(x, y, x+k-1, y+k-1) != 0) continue;
// cannot cover start/end
if (x <= sr && sr <= x+k-1 && y <= sc && sc <= y+k-1) continue;
if (x <= tr && tr <= x+k-1 && y <= tc && tc <= y+k-1) continue;
return true;
}
}
return false;
};
auto check = [&](int k) -> bool {
int HH = h - k + 1;
int WW = w - k + 1;
if (HH <= 0 || WW <= 0) return false;
// goodSquare prefix sum on top-left positions
Prefix2D sqPS(HH, WW);
sqPS.build([&](int x, int y) {
if (wallPS.sum(x, y, x+k-1, y+k-1) != 0) return 0;
// cannot cover start/end
if (x <= sr && sr <= x+k-1 && y <= sc && sc <= y+k-1) return 0;
if (x <= tr && tr <= x+k-1 && y <= tc && tc <= y+k-1) return 0;
return 1;
});
auto canBeCovered = [&](int i, int j) -> bool {
// query if exists goodSquare top-left in:
// x in [i-k+1, i], y in [j-k+1, j]
int x1 = i - k + 1, x2 = i;
int y1 = j - k + 1, y2 = j;
x1 = max(x1, 1); y1 = max(y1, 1);
x2 = min(x2, HH); y2 = min(y2, WW);
if (x1 > x2 || y1 > y2) return false;
return sqPS.sum(x1, y1, x2, y2) > 0;
};
// BFS on Safe cells: dot and NOT canBeCovered
if (!isDot(sr, sc) || !isDot(tr, tc)) {
// If start or target is wall, robot already cannot reach in usual meaning.
// But check() meaning for binary search: can we guarantee blocking?
// We'll just say true only if there exists a square to place (handled outside).
return true;
}
vector<char> vis((h+1)*(w+1), 0);
auto id = [&](int r, int c){ return r*(w+1) + c; };
queue<pair<int,int>> q;
auto isSafe = [&](int r, int c) -> bool {
if (!isDot(r,c)) return false;
// Start/end are never allowed to be covered by a valid square, but they might still be "coverable"
// by squares that cover them; we already excluded such squares in sqPS, so canBeCovered(sr,sc) == false.
return !canBeCovered(r,c);
};
if (isSafe(sr, sc)) {
vis[id(sr,sc)] = 1;
q.push({sr,sc});
} else {
// start itself could be coverable only by squares that include start, but those are forbidden,
// so this should not happen. Still keep robust.
vis[id(sr,sc)] = 1;
q.push({sr,sc});
}
static int dr[4] = {1,-1,0,0};
static int dc[4] = {0,0,1,-1};
while (!q.empty()) {
auto [r,c] = q.front(); q.pop();
for (int t = 0; t < 4; t++) {
int nr = r + dr[t], nc = c + dc[t];
if (nr < 1 || nr > h || nc < 1 || nc > w) continue;
if (vis[id(nr,nc)]) continue;
if (!isSafe(nr,nc)) continue;
vis[id(nr,nc)] = 1;
q.push({nr,nc});
}
}
// If target reachable using only absolutely safe cells, then cannot block with size k
return !vis[id(tr,tc)];
};
int lo = 1, hi = min(w,h);
int ans = -1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (existsSquare(mid) && check(mid)) {
ans = mid;
hi = mid - 1;
} else {
lo = mid + 1;
}
}
if (ans == -1) cout << "Impossible\n";
else cout << ans << "\n";
return 0;
}
Bình luận