01/10/2018, 17:41

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.

Người bí ẩn viết 19:45 ngày 01/10/2018

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).

Bài liên quan
0