BOI 2014 - Cop and Robber
Xem PDFTình hình tội phạm ở thành phố Bytemore đang trở nên nghiêm trọng. Những vụ cướp xảy ra hằng ngày, và một cảnh sát tuần tra phải đuổi theo tên cướp qua các con hẻm nối những góc phố. Vì thuộc đường hơn cảnh sát, những tên cướp thường trốn thoát. Sở cảnh sát đã lập bản đồ thành phố và muốn dùng máy tính để tìm chiến lược truy đuổi.
Cuộc truy đuổi giữa một cảnh sát và một tên cướp được mô hình hóa như sau:
- Cảnh sát chọn một góc phố để tuần tra.
- Tên cướp biết vị trí cảnh sát và chọn một góc phố để thực hiện vụ cướp. Kể từ đây, cả hai luôn biết vị trí của nhau.
- Trong lượt của mình, cảnh sát có thể đi đến một góc phố kề, tức là được nối với vị trí hiện tại bằng một con hẻm, hoặc đứng yên.
- Trong lượt của mình, tên cướp phải đi đến một góc phố kề. Khác với cảnh sát, tên cướp không được đứng yên.
- Hai bên lần lượt đi, bắt đầu bằng cảnh sát. Nếu sau lượt đi của một trong hai bên, họ ở cùng một góc phố, cảnh sát bắt được tên cướp. Nếu một trạng thái lặp lại, tên cướp trốn thoát. Một trạng thái gồm vị trí của cả hai người và bên sẽ đi tiếp; trạng thái lặp lại tương ứng với việc tên cướp có thể tránh cảnh sát mãi mãi.
Cho bản đồ thành phố, hãy xác định liệu cảnh sát có thể bảo đảm bắt được tên cướp hay không. Nếu có, chương trình phải thực hiện các nước đi của cảnh sát để bắt hắn. Luôn giả sử tên cướp chơi tối ưu.
Cài đặt
Đây là bài lập trình theo giao diện hàm. Với giao diện C++, nộp tệp mã nguồn có #include "coprobber.h" và cài đặt hai hàm sau; không viết hàm main:
int start(int N, bool A[MAX_N][MAX_N]);
int nextMove(int R);
Hằng MAX_N bằng \(500\).
Hàm start nhận:
- \(N\): số góc phố, được đánh số từ \(0\) đến \(N-1\).
- \(A\): ma trận kề. Với \(0 \le i,j<N\),
A[i][j]bằngtruenếu có con hẻm nối \(i\) và \(j\), và bằngfalsenếu không có.
Mọi con hẻm đều đi được theo hai chiều: A[i][j] == A[j][i]. Không có hẻm nối một góc phố với chính nó, nên A[i][i] luôn bằng false. Có thể đi từ một góc phố bất kỳ đến mọi góc phố khác qua các con hẻm.
Nếu có thể bảo đảm bắt được tên cướp, start phải trả về số hiệu góc phố mà cảnh sát chọn làm vị trí ban đầu. Nếu không thể, hàm phải trả về \(-1\).
Hàm nextMove(R) nhận vị trí hiện tại \(R\) của tên cướp và phải trả về góc phố mà cảnh sát đứng sau lượt đi của mình.
start được gọi đúng một lần, trước mọi lần gọi nextMove. Nếu start trả về \(-1\), nextMove không được gọi. Ngược lại, nextMove được gọi nhiều lần cho đến khi một trong các trường hợp sau xảy ra: trả về nước đi không hợp lệ, trạng thái lặp lại, hoặc tên cướp bị bắt.
Gói thử nghiệm kèm theo cung cấp giao diện C++ và một chương trình chấm mẫu được dựng lại từ mô tả này. Chương trình chấm mẫu dùng để thử trên máy cá nhân.
Ràng buộc
- \(2 \le N \le 500\).
- Ma trận \(A\) mô tả một đồ thị vô hướng liên thông, không có khuyên.
- Tên cướp phải di chuyển trong mỗi lượt; cảnh sát được phép đứng yên.
Phân nhóm
- 16 điểm: \(2 \le N \le 500\). Giữa mỗi cặp góc phố có đúng một đường đi đơn qua các con hẻm; mạng lưới là một cây.
-
14 điểm: \(2 \le N \le 500\). Mạng lưới có dạng lưới chữ nhật với ít nhất hai hàng và hai cột. Các góc phố được đánh số liên tiếp từ trái sang phải trong mỗi hàng, các hàng từ trên xuống dưới. Cụ thể, với lưới có \(w\) cột, góc ở hàng \(r\), cột \(c\) có số hiệu \(rw+c\) (hàng và cột bắt đầu từ \(0\)); hai góc nối nhau khi kề theo chiều ngang hoặc dọc.
-
30 điểm: \(2 \le N \le 100\).
- 40 điểm: \(2 \le N \le 500\).
Bài làm cần đáp ứng hai yêu cầu: xác định đúng liệu cảnh sát có thể bắt được tên cướp hay không; và nếu có thể thì thực sự bắt được tên cướp bằng các nước đi đã trả về.
Trong phân nhóm 1 và 2, phải đáp ứng cả hai yêu cầu mới được điểm. Trong phân nhóm 3 và 4, nếu chỉ đáp ứng yêu cầu thứ nhất, bài làm được 30% số điểm của phân nhóm. Để chỉ lấy điểm phần xác định, có thể kết thúc bằng cách trả về một nước đi không hợp lệ, chẳng hạn trả về \(-1\) trong nextMove.
Muốn được bất kỳ số điểm nào, chương trình vẫn phải đáp ứng các giới hạn thực thi và không xảy ra lỗi khi chạy.
Ví dụ
Ví dụ 1
start(4, [[0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]) -> 3
nextMove(1) -> 3
nextMove(0) -> 0
Giải thích
Trong lời gọi start, \(0\) và \(1\) lần lượt biểu diễn false và true. Ở đồ thị này, cảnh sát có thể chọn góc phố bất kỳ làm vị trí ban đầu. Nếu bắt đầu ở góc \(0\), cảnh sát có thể đứng yên trong lượt đầu để tên cướp chạy đến đó. Nếu bắt đầu ở một góc khác, cảnh sát có thể chờ tên cướp đến góc \(0\) rồi đi tới bắt hắn.
Thử nghiệm
Chương trình chấm mẫu đọc dữ liệu từ đầu vào chuẩn theo định dạng sau:
- Dòng đầu chứa \(N\).
- \(N\) dòng tiếp theo chứa ma trận \(A\), mỗi dòng gồm \(N\) số \(0\) hoặc \(1\). Ma trận đối xứng và các phần tử trên đường chéo chính bằng \(0\).
- Dòng tiếp theo chứa \(1\) nếu cảnh sát có thể bắt được tên cướp, hoặc \(0\) nếu không thể.
- Nếu giá trị trên bằng \(1\), có thêm \(N\) dòng mô tả chiến lược tên cướp, mỗi dòng gồm \(N+1\) số nguyên từ \(0\) đến \(N-1\).
Trong bảng chiến lược, chỉ số hàng và cột bắt đầu từ \(0\). Giá trị tại hàng \(c\), cột \(r<N\) là góc phố mà tên cướp đi tới khi đến lượt hắn, cảnh sát ở \(c\) và tên cướp ở \(r\). Các phần tử đường chéo bị bỏ qua vì khi đó tên cướp đã bị bắt. Giá trị cuối cùng trên hàng \(c\) là vị trí ban đầu của tên cướp khi cảnh sát bắt đầu ở \(c\).
Tệp sample1.in mô tả ba góc phố đôi một nối với nhau:
3
0 1 1
1 0 1
1 1 0
1
0 2 1 2
2 0 0 2
1 0 0 1
Tệp sample2.in tương ứng với ví dụ gọi hàm ở trên:
4
0 1 1 1
1 0 0 0
1 0 0 0
1 0 0 0
1
0 0 0 0 1
2 0 0 0 2
3 0 0 0 3
1 0 0 0 1
Với chương trình chấm mẫu kèm theo, kết quả OK biểu thị hoàn thành yêu cầu; PARTFAIL biểu thị xác định đúng khả năng bắt nhưng chưa bắt được tên cướp; FAIL biểu thị không đạt. Điểm phần xác định còn phụ thuộc phân nhóm như đã nêu ở trên. Đây là kết quả của chương trình chấm mẫu; hai hàm bạn cài đặt chỉ cần trả về các giá trị theo giao diện.
Kỳ thi:
- BOI 2014 - Ngày 1 (1 Tháng 1., 2014)



Bình luận