[C + +] backtracking method uses reference passing, lambda expression, vector Back() use

Posted by Jyotsna on Sat, 05 Feb 2022 19:31:11 +0100

1219. Gold miners
You want to develop a gold mine. Geological surveyors have identified the distribution of resources in the gold mine and marked it with a grid of size m * n. The integer in each cell represents the amount of gold in this cell; If the cell is empty, it is 0.

In order to maximize profits, miners need to mine gold according to the following rules:

Every time a miner enters a cell, he collects all the gold in that cell.
Miners can walk up, down, left and right from their current position at a time.
Each cell can only be mined (entered) once.
Do not mine (enter) cells with a gold number of 0.
Miners can start from any cell with gold in the grid or stop.

Example 1:

Input: grid = [[0,6,0],[5,8,7],[0,9,0]]
Output: 24
Explanation:
[[0,6,0],
[5,8,7],
[0,9,0]]
One route to collect the most gold is: 9 - > 8 - > 7.
Example 2:

Input: grid = [[1,0,7],[2,0,6],[3,4,5],[0,3,0],[9,0,20]]
Output: 28
Explanation:
[[1,0,7],
[2,0,6],
[3,4,5],
[0,3,0],
[9,0,20]]
One route to collect the most gold is: 1 - > 2 - > 3 - > 4 - > 5 - > 6 - > 7.

Tips:

1 <= grid.length, grid[i].length <= 15
0 <= grid[i][j] <= 100
There is gold in up to 25 cells.

At the beginning, I just wanted recursion and backtracking
But I thought it was troublesome, so I used value passing

class Solution {
private:
    vector<vector<int>> _grid;

    int getGold(int i, int j, vector<vector<int>> flagCache, int totalGold)
    {
        if(i<0||j<0)
            return totalGold;
        if(i>=_grid.size())
            return totalGold;
        if(j>=_grid[i].size())
            return totalGold;

        if(_grid[i][j] == 0||flagCache[i][j] == 1)
            return totalGold;
        
        flagCache[i][j] = 1;

        vector<int> goldNumCache;

        goldNumCache.push_back(getGold(i-1,j,flagCache,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i+1,j,flagCache,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i,j-1,flagCache,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i,j+1,flagCache,totalGold + _grid[i][j]));
        sort(goldNumCache.begin(),goldNumCache.end());

        return goldNumCache.back();
    }
public:
    int getMaximumGold(vector<vector<int>>& grid) {

        _grid = grid;
        vector<vector<int>> _flag = vector<vector<int>>(grid.size());
        for(int i=0;i<grid.size();i++)
            _flag[i] = vector<int>(grid[i].size());

        vector<int> goldNum;

        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[i].size();j++)
            {
                goldNum.push_back(getGold(i,j,_flag,0));
            }
        }

        sort(goldNum.begin(),goldNum.end());
        return goldNum.back();
    }
};

After changing to reference passing, I originally thought of backtracking after calling the function recursively

    int getGold(int i, int j, int totalGold)
    {
        if(i<0||j<0)
            return totalGold;
        if(i>=_grid.size())
            return totalGold;
        if(j>=_grid[i].size())
            return totalGold;

        if(_grid[i][j] == 0||_flag[i][j] == 1)
            return totalGold;
        
        _flag[i][j] = 1;

        vector<int> goldNumCache;

        // recursion
        goldNumCache.push_back(getGold(i-1,j,totalGold + _grid[i][j]));
        // to flash back
        if(goldNumCache.back() != totalGold + _grid[i][j])
            _flag[i-1][j] = 0;
        // recursion
        goldNumCache.push_back(getGold(i+1,j,totalGold + _grid[i][j]));
        // to flash back
        if(goldNumCache.back() != totalGold + _grid[i][j])
            _flag[i+1][j] = 0;
        // recursion
        goldNumCache.push_back(getGold(i,j-1,totalGold + _grid[i][j]));
        // to flash back
        if(goldNumCache.back() != totalGold + _grid[i][j])
            _flag[i][j-1] = 0;
        // recursion
        goldNumCache.push_back(getGold(i,j+1,totalGold + _grid[i][j]));
        // to flash back
        if(goldNumCache.back() != totalGold + _grid[i][j])
            _flag[i][j+1] = 0;
        
        sort(goldNumCache.begin(),goldNumCache.end());

        return goldNumCache.back();
    }
    

Then it's wrong
I'm still thinking about what's wrong... But I suddenly found that I don't have to think about this. It's troublesome in itself
Originally, the simplest should be to trace back when returning the function
Just mind your own state. This principle should be observed
And it does allow this, and my backtracking is reasonable after recursive calls

    int getGold(int i, int j, int totalGold)
    {
        if(i<0||j<0)
            return totalGold;
        if(i>=_grid.size())
            return totalGold;
        if(j>=_grid[i].size())
            return totalGold;

        if(_grid[i][j] == 0||_flag[i][j] == 1)
            return totalGold;
        
        _flag[i][j] = 1;

        vector<int> goldNumCache;

        // recursion
        goldNumCache.push_back(getGold(i-1,j,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i+1,j,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i,j-1,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i,j+1,totalGold + _grid[i][j]));
        
        sort(goldNumCache.begin(),goldNumCache.end());

        _flag[i][j] = 0;

        return goldNumCache.back();
    }
    

Final code:

class Solution {
private:
    vector<vector<int>> _grid;
    vector<vector<int>> _flag;

    int getGold(int i, int j, int totalGold)
    {
        if(i<0||j<0)
            return totalGold;
        if(i>=_grid.size())
            return totalGold;
        if(j>=_grid[i].size())
            return totalGold;

        if(_grid[i][j] == 0||_flag[i][j] == 1)
            return totalGold;
        
        _flag[i][j] = 1;

        vector<int> goldNumCache;

        // recursion
        goldNumCache.push_back(getGold(i-1,j,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i+1,j,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i,j-1,totalGold + _grid[i][j]));
        goldNumCache.push_back(getGold(i,j+1,totalGold + _grid[i][j]));
        
        sort(goldNumCache.begin(),goldNumCache.end());

        _flag[i][j] = 0;

        return goldNumCache.back();
    }
public:
    int getMaximumGold(vector<vector<int>>& grid) {

        _grid = grid;
        _flag = vector<vector<int>>(grid.size());
        for(int i=0;i<grid.size();i++)
            _flag[i] = vector<int>(grid[i].size());

        vector<int> goldNum;

        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[i].size();j++)
            {
                goldNum.push_back(getGold(i,j,0));
            }
        }

        sort(goldNum.begin(),goldNum.end());
        return goldNum.back();
    }
};

Still overtime... I don't know why
After reading other people's solutions, I feel the same as mine

Others don't use flag and set grid to 0 instead. I'll try

class Solution {
private:
    vector<vector<int>> _grid;

    int getGold(int i, int j, int totalGold)
    {
        if(i<0||j<0)
            return totalGold;
        if(i>=_grid.size())
            return totalGold;
        if(j>=_grid[i].size())
            return totalGold;

        if(_grid[i][j] == 0)
            return totalGold;
        
        int goldCache = _grid[i][j];
        _grid[i][j] = 0;

        vector<int> goldNumCache;

        // recursion
        goldNumCache.push_back(getGold(i-1,j,totalGold + goldCache));
        goldNumCache.push_back(getGold(i+1,j,totalGold + goldCache));
        goldNumCache.push_back(getGold(i,j-1,totalGold + goldCache));
        goldNumCache.push_back(getGold(i,j+1,totalGold + goldCache));
        
        sort(goldNumCache.begin(),goldNumCache.end());

        _grid[i][j] = goldCache;

        return goldNumCache.back();
    }
public:
    int getMaximumGold(vector<vector<int>>& grid) {

        _grid = grid;

        vector<int> goldNum;

        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[i].size();j++)
            {
                goldNum.push_back(getGold(i,j,0));
            }
        }

        sort(goldNum.begin(),goldNum.end());
        return goldNum.back();
    }
};

Or overtime... Thinking
Let me look at other people's solutions

Others first judge whether the next grid can go, and then call the function
I call the function first and then judge my state
I remember that it seems that calling functions also takes time, so there is inline
Let me try again

class Solution {
private:
    static constexpr int delta[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

public:
    int getMaximumGold(vector<vector<int>>& grid) {

        function<int(int,int,int)> getGold = [&](int x, int y, int totalGold)
        {
            vector<int> totalGoldCache;

            int goldCache = grid[x][y];
            grid[x][y] = 0;

            // recursion
            for(int i=0;i<4;i++)
            {
                int nx = x + delta[i][0];
                int ny = y + delta[i][1];
                if((nx >= 0) && (ny >= 0) && (nx < grid.size()))
                    if(ny < grid[nx].size())
                        if(grid[nx][ny] != 0)
                            totalGoldCache.push_back(getGold(nx, ny, totalGold + goldCache));
            }

            sort(totalGoldCache.begin(), totalGoldCache.end());

            grid[x][y] = goldCache;

            return totalGoldCache.back();
        };

        vector<int> goldNum;

        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[i].size();j++)
            {
                if(grid[i][j] != 0)
                    goldNum.push_back(getGold(i,j,0));
            }
        }

        sort(goldNum.begin(),goldNum.end());
        return goldNum.back();
    }
};

This will make an error... Because there may not be a value when taking the back of the vector
You also need to add a default value in advance

class Solution {
private:
    static constexpr int delta[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

public:
    int getMaximumGold(vector<vector<int>>& grid) {
        
        int m = grid.size(), n = grid[0].size();

        function<int(int,int,int)> getGold = [&](int x, int y, int totalGold)
        {
            vector<int> totalGoldCache;

            int goldCache = grid[x][y];
            grid[x][y] = 0;

            // recursion
            for(int i=0;i<4;i++)
            {
                int nx = x + delta[i][0];
                int ny = y + delta[i][1];
                if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] > 0)
                    totalGoldCache.push_back(getGold(nx, ny, totalGold + goldCache));
            }

            totalGoldCache.push_back(totalGold + goldCache);
            sort(totalGoldCache.begin(), totalGoldCache.end());

            grid[x][y] = goldCache;

            return totalGoldCache.back();
        };

        vector<int> totalGoldCache2;

        for(int i=0;i<grid.size();i++)
        {
            for(int j=0;j<grid[i].size();j++)
            {
                if(grid[i][j] != 0)
                    totalGoldCache2.push_back(getGold(i,j,0));
            }
        }

        totalGoldCache2.push_back(0);
        sort(totalGoldCache2.begin(),totalGoldCache2.end());
        return totalGoldCache2.back();
    }
};

That's good

Topics: C++ Back-end