Tìm từ
Đề bài
Cho một bảng $n \times m$ gồm các chữ cái. Có $q$ xâu $s$ cần tìm, với từng xâu $s$ hãy kiểm tra xem xâu có tồn tại trong bảng không. Từ được cho là tồn tại trong bảng nếu nó được ghép bởi các ký tự liên tiếp cùng nằm trên một hàng hoặc một cột, nhưng không được cả hai.
Xét bảng sau:
abc
def
ghi
Trong bảng này:
- Từ
abcnằm trên dòng đầu tiên khi đọc từ trái qua phải. - Từ
cbnằm trên dòng đầu tiên khi đọc từ phải qua trái. - Từ
adnằm trên cột đầu tiên khi đọc từ trên xuống dưới. - Từ
bcfkhông nằm trên bảng, vì muốn có được từbcf, ta phải di chuyển trên cả hàng và cột. - Từ
henằm trên cột thứ hai khi đọc từ dưới lên trên. - Từ
ebnằm trên cột thứ hai khi đọc từ dưới lên trên.
Dữ liệu nhập:
- Dòng đầu tiên gồm hai số nguyên $n, m$ – ma trận có $n$ dòng, $m$ cột.
- $n$ dòng tiếp theo, mỗi dòng có $m$ chữ cái.
- Dòng tiếp theo là số nguyên $q$ – số xâu cần tìm.
- $q$ dòng tiếp theo, mỗi dòng là một xâu $s$ cần tìm.
Dữ liệu xuất: gồm $q$ dòng, mỗi dòng in ra YES nếu từ có tồn tại, ngược lại in ra NO.
Điều kiện: $1 \le n, m, q, \text{length}(s) \le 50$.
Giải thích ví dụ: marisa có trên cột đầu tiên từ trên xuống; sama có trên cột cuối cùng từ dòng 2 trở xuống; laptrinh không tìm thấy; ira có ở dòng thứ hai từ phải qua trái; ama có ở cột cuối cùng từ dưới lên trên.
6 4
mari
aris
risa
isam
sama
amar
5
marisa
sama
laptrinh
ira
amaYES
YES
NO
YES
YESLời mở đầu
Đây là trò "tìm chữ" quen thuộc trên báo giấy, nhưng dễ hơn một chút: từ chỉ được nằm thẳng trên một hàng hoặc một cột (không có đường chéo, không được bẻ góc). Bài giúp các bạn luyện hai kỹ năng: duyệt theo hướng trên mảng 2 chiều (giống bài Caro) và tìm xâu con. Mình giải bằng 2 cách và chạy cả hai trên bộ test thật – có một điều thú vị: cùng một ý tưởng vét cạn, bản C++ qua hết nhưng bản Python lại bị quá thời gian.
Bấm vào nút bên dưới để nộp bài và được hệ thống CLUE OJ chấm tự động.
Nộp bài trên CLUE OJLộ trình lời giải, bấm vào từng phần để nhảy tới:
Bộ testBộ test chính thức có gì?
| Nhóm | Các test | $n \times m$ | $q$ | Độ dài $s$ lớn nhất | Tỉ lệ YES | Cách 1 C++ | Cách 1 Python | Cách 2 |
|---|---|---|---|---|---|---|---|---|
| Nhỏ | 1 – 30 | 5…10 × 5…10 | 5 … 10 | 9 | 155/220 | 30/30 | 30/30 | 30/30 |
| Lớn | 31 – 100 | đúng 50 × 50 | 10 … 49 | 51 | 1430/2018 | 70/70 | TLE nhiều test | 70/70 |
Đề không chia subtask, nhưng bộ test tách rõ 2 nhóm: 30 test nhỏ (bảng tối đa $10 \times 10$) và 70 test lớn đều là bảng $50 \times 50$. Vài điều mình để ý:
- Bảng dùng cả chữ hoa và chữ thường (ở test lớn có đủ 52 loại chữ), và đáp án phân biệt hoa/thường – so sánh ký tự trực tiếp là đúng, đừng đổi hết về chữ thường.
- Có 186 truy vấn chỉ 1 ký tự – chỉ cần chữ đó có trong bảng.
- Có 1 truy vấn dài 51 ký tự (vượt giới hạn 50 của đề một chút, ở test 73) – dài hơn mọi hàng/cột nên đáp án là
NO; code phải không bị truy cập ngoài mảng ở trường hợp này. - Tổng cộng 2238 truy vấn, 1585 câu trả lời
YES(khoảng 70%).
Ý tưởngMỗi ô là một điểm xuất phát, thử 4 hướng
Nếu xâu $s$ có trong bảng thì chữ $s_0$ nằm ở một ô $(i, j)$ nào đó, và các chữ tiếp theo $s_1, s_2, \dots$ nằm liên tiếp theo một trong 4 hướng: sang phải, sang trái, xuống dưới, lên trên. Vì vậy:
YES.Khác với bài Caro, ở đây phải thử đủ 4 hướng chứ không chỉ 2, vì từ có thể đọc ngược (phải qua trái, dưới lên trên): he chỉ đọc được từ dưới lên. Còn "không được cả hai" nghĩa là trên một lần đọc thì hướng không đổi – vòng lặp $k$ luôn đi theo một hướng cố định nên điều kiện này tự thoả.
Em nhập bảng và từ cần tìm rồi bấm Tiếp để xem máy thử từng ô có chữ cái đầu khớp và từng hướng (để gọn, các ô có chữ đầu không khớp mình bỏ qua):
Cách 1Vét cạn: mọi ô × 4 hướng
Hàm khop(s, i, j, d) kiểm tra xâu s có đọc được bắt đầu tại ô (i, j) theo hướng d không. Hàm main thử mọi ô, mọi hướng; biến co dùng để dừng sớm ngay khi tìm thấy.
khop được gộp thành 1 bước.- Điều kiện ra ngoài bảng được kiểm tra trước
g[x][y] != s[k](ngắt mạch||), giống bài Caro. - Hàm
khoptrả vềfalsengay khi gặp ký tự sai đầu tiên, nên thực tế phần lớn các lần gọi chỉ so 1 ký tự (chữ đầu không khớp). - Xâu có 1 ký tự: chỉ cần chữ đó xuất hiện trong bảng là
YES(bộ test có 186 truy vấn như vậy).
Kết quả chạy thật: bản C++ đúng 100/100 test, chậm nhất 0.08 giây. Bản Python cùng ý tưởng đúng hết 30 test nhỏ nhưng quá thời gian 1 giây ở nhiều test 50 × 50 (máy mình chấm 2 lần được 84/100 và 62/100, chậm nhất gần 2 giây) – Python chạy vòng lặp lồng nhau chậm hơn C++ hàng chục lần.
Cách 2Gom các hàng, cột (và bản đọc ngược) rồi tìm xâu con
Đổi góc nhìn: một từ "nằm trên hàng $i$ đọc từ trái qua phải" chính là một xâu con liên tiếp của xâu hàng $i$. Vậy mình gom sẵn tất cả các "dòng chữ" có thể đọc được:
- $n$ xâu hàng (đọc trái → phải) và $m$ xâu cột (đọc trên → dưới);
- đảo ngược cả $n + m$ xâu đó để có thêm các hướng phải → trái và dưới → trên.
Tổng cộng $2(n + m)$ xâu. Với mỗi truy vấn, chỉ cần hỏi "$s$ có là xâu con của xâu nào trong danh sách không" – C++ có sẵn x.find(s), Python có s in x.
find là một lần xét một xâu x trong ds; vùng tô xanh là chỗ tìm thấy s.x.find(s)trả về vị trí đầu tiên củastrongx, hoặcstring::nposnếu không có.- Vòng đảo ngược dùng
sz = ds.size()lưu trước, vì trong lúc lặp mìnhpush_backthêm vàods– nếu viếtt < ds.size()thì vòng lặp sẽ không bao giờ dừng. - Xâu dài hơn mọi hàng/cột (bộ test có 1 truy vấn dài 51 ký tự) thì
findtự trả về không tìm thấy.
Kết quả chạy thật: bản C++ đúng 100/100 test, chậm nhất 0.04 giây; bản Python đúng 100/100 test, chậm nhất 0.29 giây – nhờ phép in được cài đặt bên trong bằng C nên rất nhanh.
Lỗi hay gặpChỉ đọc xuôi
d thành d += 2 (chỉ còn hướng phải, xuống) và chấm lại: chỉ đúng 10/100 test, vì gần như test nào cũng có từ đọc ngược như ira, ama trong ví dụ.- Không biết học gì trước, học gì sau, học lan man nên kiến thức bị hổng.
- Bí bài không ai gỡ, ngồi cả buổi vẫn không ra rồi bỏ cuộc.
- Code chạy được nhưng không đủ điểm, không biết sai ở đâu, chậm ở đâu.
- Không có đề thi thử và người chấm, nên không biết mình đang ở mức nào.
- Dễ nản giữa chừng khi không có ai theo sát.
- Lộ trình 111 buổi video sắp sẵn từ dòng code đầu tiên đến đề HSG thật của các tỉnh.
- Thầy trực tiếp gỡ bí, chữa bài cho từng em qua nhóm Zalo riêng.
- Hệ thống chấm bài tự động 24/7 và thi thử HSG hằng tuần để biết chính xác mình đang ở đâu.
- Đóng học phí một lần, thầy kèm lâu dài: từ thi chuyên Tin đến HSG quốc gia và cả khi lên đại học.
Nhận xét
Đăng nhận xét