DFS:深搜+回溯+剪枝解决矩阵搜索问题

创作不易,感谢三连!!

一、N皇后

. - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    vector<vector<string>> ret;
    vector<string> path;
    bool checkcol[9];
    bool checkdig1[18];
    bool checkdig2[18];
    int n;
    vector<vector<string>> solveNQueens(int _n) 
    {
        n=_n;
        path.resize(n);
        for(int i=0;i<n;++i)  path[i].append(n,'.');//先全部初始化成.
         dfs(0);
         return ret;
    }

    void dfs(int row)
    {
        if(row==n) {ret.push_back(path);return;}
        for(int col=0;col<n;++col)//枚举每一行的每个元素
        {
            if(checkcol[col]==false&&checkdig1[n+row-col]==false&&checkdig2[row+col]==false)//n+row-col防止越界
            {
               path[row][col]='Q';
               checkcol[col]=checkdig1[n+row-col]=checkdig2[row+col]=true;
                dfs(row+1);
                //恢复现场
               path[row][col]='.';
               checkcol[col]=checkdig1[n+row-col]=checkdig2[row+col]=false;
            }
        }
    }
};

二、有效的数独

. - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    bool checkrow[9][10];
    bool checkcol[9][10];
    bool checkgrid[3][3][10];
    bool isValidSudoku(vector<vector<char>>& board) 
    {
         for(int row=0;row<9;++row)
         {
            for(int col=0;col<9;++col)
            {
                if(board[row][col]!='.')
                {
                    int num=board[row][col]-'0';
                    if(checkrow[row][num]||checkcol[col][num]||checkgrid[row/3][col/3][num]) return false;
                    checkrow[row][num]=checkcol[col][num]=checkgrid[row/3][col/3][num]=true;
                }
            }
         }
         return true;
    }
};

三、解数独

. - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    bool checkrow[9][10];
    bool checkcol[9][10];
    bool checkgrid[3][3][10];
    void solveSudoku(vector<vector<char>>& board) 
    {
        //初始化
       for(int row=0;row<9;++row)
         for(int col=0;col<9;++col)
         {
            if(board[row][col]!='.')
            {
                int num=board[row][col]-'0';
                checkrow[row][num]=checkcol[col][num]=checkgrid[row/3][col/3][num]=true;
            }
         }
        dfs(board);
    }
        bool dfs(vector<vector<char>> &board)//bool用来告诉上一层决策是正确的
         {
           for(int row=0;row<9;++row)
            for(int col=0;col<9;++col)
         {
            if(board[row][col]=='.')
            {
              //开始尝试填数
              for(int num=1;num<=9;++num)
              {
                if(!checkrow[row][num]&&!checkcol[col][num]&&!checkgrid[row/3][col/3][num])
                {
                    //说明能填,就填上
                    board[row][col]=num+'0';
                    checkrow[row][num]=checkcol[col][num]=checkgrid[row/3][col/3][num]=true;
                    if(dfs(board)) return true;//去下一个位置填,如果填成功了,返回true
                    //恢复现场
                    board[row][col]='.';
                    checkrow[row][num]=checkcol[col][num]=checkgrid[row/3][col/3][num]=false;
                }
              }
              return false;//1-9没有一个数能填,说明决策错误
            }
         }
            return true;//安全地填完了,返回true
         }
};

四、单词搜索

. - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    bool check[6][6];//用来标记选过的位置
    int m,n;
    vector<vector<char>> board;
    string word;
    bool exist(vector<vector<char>>& _board, string _word) 
    {
        board=_board;
        word=_word;
        m=board.size();
        n=board[0].size();
        for(int i=0;i<m;++i)
         for(int j=0;j<n;++j)
          {
             if(board[i][j]==word[0])
             {
                check[i][j]=true;
                if(dfs(i,j,1))  return true;
                check[i][j]=false;
             }
          }
          return false;
    }
    //用向量的方式来定义
     int dx[4]={0,0,-1,1};
     int dy[4]={1,-1,0,0}; //就可以将4个方向改变成一个for循环
    bool dfs(int i,int j,int pos)
    {
        if(pos==word.size())  return true;
        for(int k=0;k<4;++k)
        {
           int x=i+dx[k],y=j+dy[k];
           if(x>=0&&x<m&&y>=0&&y<n&&check[x][y]==false&&board[x][y]==word[pos])
           {
               check[x][y]=true;
               if(dfs(x,y,pos+1)) return true;
               check[x][y]=false;
           }
        }
        return false;//如果四个方向都找不到,说明确实没有可填的数,直接返回
    }
};

五、黄金旷工

. - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int ret=0;
    bool check[15][15];
    int m,n;
    int getMaximumGold(vector<vector<int>>& grid) 
    {
      m=grid.size();
      n=grid[0].size();
      for(int i=0;i<m;++i)
        for(int j=0;j<n;++j)
          {
            if(grid[i][j])
            {
                check[i][j]=true;
                dfs(grid,i,j,grid[i][j]);
                check[i][j]=false;
            }
          }
          return ret;
     }
      //用向量的方式来定义
     int dx[4]={0,0,-1,1};
     int dy[4]={1,-1,0,0}; //就可以将4个方向改变成一个for循环
     void dfs(vector<vector<int>>& grid,int i,int j,int count)
     {
        for(int k=0;k<4;++k)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&grid[x][y])
            {
                check[x][y]=true;
                dfs(grid,x,y,count+grid[x][y]);
                check[x][y]=false;
            }
        }
        ret=max(count,ret);
        //for循环结束,确实没得填了,更新
     }
};

六、不同路径III

. - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    int ret;
    bool check[20][20];//用来标记
    int m,n,step;//step用来统计可以走的方格个数
    int uniquePathsIII(vector<vector<int>>& grid) 
    {
        ret=0;
        m=grid.size();
        n=grid[0].size();
        step=0;
        int bx=0,by=0;//记录起点
        //先找起点
        for(int i=0;i<m;++i)
          for(int j=0;j<n;++j)
            {
                if(grid[i][j]==0) ++step;
                else if(grid[i][j]==1) 
                {
                    bx=i;
                    by=j;
                }
            }
        step+=2;//把起点和终点算上,最后走到终点的时候就可以返回了
        check[bx][by]=true;
        dfs(grid,bx,by,1);
        return ret;
    }
    int dx[4]={0,0,-1,1};
    int dy[4]={1,-1,0,0}; //就可以将4个方向改变成一个for循环
    void dfs(vector<vector<int>>& grid,int i,int j,int count)
    {
        if(grid[i][j]==2&&count==step) {++ret;return;}
        for(int k=0;k<4;++k)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&grid[x][y]!=-1)
            {
                check[i][j]=true;
                dfs(grid,x,y,count+1);
                check[i][j]=false;
            }
        }
    }
};

七、小总结

1、矩阵搜索问题经常要用到向量,也就是我们可以通过dx和dy来帮助我们定义方向

2、矩阵搜索要确保走过的位置不再走过,所以此时有两个策略:

(1)标记数组,比较常用

(2)修改原矩阵的内容,但是这样做的话要我们要确保最后能够把它复原

3、dfs的返回值不一定是void,如果该题目并不只是完全地去统计,而是涉及到我们做出的选择可能会错误的时候,这个时候我们就需要通过bool类型的返回值来帮助我们判断当前的填法是否正确。比如解数独和单词搜索问题

相关推荐
jjyangyou2 分钟前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
van叶~19 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法20 分钟前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
knighthood200129 分钟前
解决:ros进行gazebo仿真,rviz没有显示传感器数据
c++·ubuntu·ros
云卓SKYDROID34 分钟前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香1 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童1 小时前
双指针算法习题解答
算法
小堇不是码农1 小时前
在VScode中配置C_C++环境
c语言·c++·vscode
Jack黄从零学c++1 小时前
C++ 的异常处理详解
c++·经验分享
想要打 Acm 的小周同学呀1 小时前
LRU缓存算法
java·算法·缓存