Tìm đường đi trong ma trận thỏa mãn yêu cần bài toán bằng quay lui
Hi mọi người. Mình có đang giải problem sau: http://ntucoder.net/Problem/Details/52
Bài trên sử dụng quay lui, ý tưởng thuật toán của mình như sau:
Do giả thuyết của đề bài nên tại 1 vị trí bất kỳ (i, j) trong ma trận (khác (1, 1) và (n, m)), ta sẽ xét 2 trường hợp là (i + 1, j) (ô bên dưới) hoặc (i, j + 1) (ô bên phải). Với mỗi trường hợp, nếu ô đang xét có giá trị -1 thì hiển nhiên ta skip. Còn không, ta sẽ dùng đệ quy để xét ô đó cho lần tiếp theo.
Vì yêu cầu là bé hái được ít nhất 2 loại nấm mà bài chỉ cho có 3 loại nên mình sẽ tạo 3 global vars lưu số lượng nấm thuộc 1 trong 3 loại đã hái được. Với cách này, ta sẽ dễ dàng check xem từ (1,1) đến (n, m) bé có lấy được ít nhất 2 loại nấm không bằng câu lệnh điều kiện sau:
if ((check1 > 0 && check2 > 0) || (check2 > 0 && check3 > 0) || (check1 > 0 && check3 > 0))
Sau cùng là giải thuật quay lui cho bài toán. Mình cài đặt code như sau: https://ideone.com/GntULZ
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
int n, m, check1 = 0, check2 = 0, check3 = 0;
vector<pair<int, int>> res;
vector<vector<int>> road;
bool findway(int row = 0, int col = 0)
{
if (row == n - 1 && col == m - 1) {
if ((check1 > 0 && check2 > 0) || (check2 > 0 && check3 > 0) || (check1 > 0 && check3 > 0)) {
res.push_back(make_pair(n, m));
return true;
}
return false;
}
// right
if (col < m - 1 && road[row][col + 1] != -1) {
res.push_back(make_pair(row + 1, col + 2));
if (road[row][col + 1] == 1) ++check1;
else if (road[row][col + 1] == 2) ++check2;
else if (road[row][col + 1] == 3) ++check3;
if (findway(row, col + 1))
return true;
}
// down
if (row < n - 1 && road[row + 1][col] != -1) {
res.push_back(make_pair(row + 2, col + 1));
if (road[row][col + 1] == 1) ++check1;
else if (road[row][col + 1] == 2) ++check2;
else if (road[row][col + 1] == 3) ++check3;
if (findway(row + 1, col))
return true;
}
// backtrack
if (road[row][col] == 1) --check1;
else if (road[row][col] == 2) --check2;
else if (road[row][col] == 3) --check3;
res.pop_back();
return false;
}
int main()
{
cin >> n >> m;
road.resize(n);
res.push_back(make_pair(1, 1));
for (int i = 0; i < n; ++i) {
road[i].resize(m);
for (int j = 0; j < m; ++j)
cin >> road[i][j];
}
if (!findway()) cout << -1;
else {
int s = res.size();
for (int i = 0; i < s; ++i)
cout << res[i].first << " " << res[i].second << endl;
}
return 0;
}
Chạy thử với 2 bộ test mẫu thì code mình chỉ đúng được test #2:
INPUT:
4 6
0 1 3 -1 -1 -1
3 3 1 -1 -1 2
-1 2 1 2 2 -1
2 2 -1 2 3 0
OUTPUT:
1 1
1 2
1 3
2 3
3 3
3 4
3 5
4 5
4 6
Còn test #1 thì không tìm được đường đi (in ra -1) mặc dù output là có đường đi:
INPUT:
3 4
0 3 -1 2
3 3 3 3
3 1 3 0
OUTPUT:
1 1
2 1
3 1
3 2
3 3
3 4
Mình vẫn chưa biết bị sai ở chỗ nào mà lại chạy được test #2 trong khi không chạy được test #1. Code sử dụng global vars nên mình gặp khó khăn trong việc debug. Nhờ mọi người xem bài này và code giải của mình giúp xem sai ở chỗ nào ạ !
Xin cảm ơn.
Chỉnh lại chỗ câu if trong xét ô dưới
[row][col + 1]
thành[row + 1][col]
, bị nhầm chỗ đó đấy!Trong câu if đầu tiên của hàm, bỏ vào
res.pop_back()
nếu câu if ko được thỏa mãn để nó rút đi cái pair (n, m).