算法妙妙屋-------2..回溯的奇妙律动

回溯算法是一种用于系统性地搜索和解决问题的算法,它以深度优先搜索(DFS)为基础,用来探索所有可能的解决方案。通过递归地尝试候选解并在必要时回退(即"回溯"),它能够高效地解决许多涉及组合、排列和分割问题的场景。

核心思想

  1. 递归:回溯算法通常以递归方式实现,每次深入问题的一个分支。
  2. 状态空间树:将问题抽象成一个树形结构,每个节点代表一个部分解或状态。
  3. 剪枝:在探索过程中,提前排除不可能的解以减少计算量。
  4. 回退:当某一条路径无法产生有效解时,返回上一步并尝试其他路径。

典型应用

  • 排列与组合问题:如求全排列、子集生成。
  • 路径搜索问题:如迷宫问题、数独求解。
  • 优化问题:如0/1背包问题。
  • 约束满足问题:如八皇后问题、图着色问题。

算法流程

  1. 选择:选择一个可能的路径或解分支。
  2. 约束检查:判断当前选择是否满足问题的约束条件。
  3. 递归搜索:继续深入探索下一个状态。
  4. 回溯:若当前选择无效,则返回上一步重新选择。

优势与不足

  • 优势:实现简单,适合解决所有可能解的穷举问题。
  • 不足:在问题规模较大时,计算复杂度可能过高,需要结合剪枝优化。

简单示例(伪代码):

python 复制代码
def backtrack(path, options):
    if 满足结束条件:
        记录结果
        return
    for option in options:
        做选择
        backtrack(新的路径, 剩余选择)
        撤销选择

通过以上步骤,回溯算法能够在复杂解空间中寻找问题的最优解或所有可能解。

1.单词搜索

题目链接:单词搜索

解题思路:

  • 1.将整个数组向外扩充一环(避免讨论边缘问题
  • 2.进行深度优先搜索
cpp 复制代码
class Solution {
public:

bool dfs(vector<vector<char>>& square, string word,int position,int i,int j,vector<vector<bool>>& check)
{
  if(position==word.size())
  return true;

  if(square[i][j+1]==word[position]&&!check[i][j+1])//判断右
  {
      check[i][j+1]=true;
      if(dfs(square, word,position+1,i,j+1,check))
      {
        return true;//这种类型的题目需要return,因为只需查找一个即可满足题意。
      }
      else
      {
        check[i][j+1]=false;
      }
  }
   
   if(square[i][j-1]==word[position]&&!check[i][j-1])//判断左
  {
      check[i][j-1]=true;
      if(dfs(square, word,position+1,i,j-1,check))
      {
        return true;
      }
      else
      {
        check[i][j-1]=false;
      }
  }

  if(square[i+1][j]==word[position]&&!check[i+1][j])//判断下
  {
      check[i+1][j]=true;
      if(dfs(square, word,position+1,i+1,j,check))
      {
        return true;
      }
      else
      {
        check[i+1][j]=false;
      }
  }


  if(square[i-1][j]==word[position]&&!check[i-1][j])//判断上
  {
      check[i-1][j]=true;
      if(dfs(square, word,position+1,i-1,j,check))
      {
        return true;
      }

      else
      {
        check[i-1][j]=false;
      }
  }
  return false;
}


    bool exist(vector<vector<char>>& board, string word) {
        int row=board.size();
        int line=board[0].size();
        vector<vector<bool>>check(row+2,vector<bool>(line+2,false));//初始化二维数组
        vector<vector<char>>square(row+2,vector<char>(line+2,'0'));

        for(int i=1;i<row+1;i++)
        {
           for(int j=1;j<line+1;j++)
           {
               square[i][j]=board[i-1][j-1];
           }
        }

        for(int i=1;i<row+1;i++)
        {
           for(int j=1;j<line+1;j++)
           {
               if(square[i][j]==word[0])
               {
                   check[i][j]=true;
                  if(dfs(square,word,1,i,j,check))
                  {
                    return true;
                  }
                   check[i][j]=false;  //恢复现场
               }
           }
        }
        return false;
    }
};

2.黄金矿工

题目链接:黄金矿工

解题思路:

  • 枚举矩阵中所有的位置当成起点,来⼀次深度优先遍历,统计出所有情况下能收集到的⻩⾦数的最⼤值即可。
cpp 复制代码
class Solution {
public:

 
 int maximum=0;
 int sum=0;


    void dfs(vector<vector<int>>& square,int i,int j,vector<vector<bool>>& check)//不需要return,因为要全部遍历一遍才能找到最优解
    {
       if(square[i][j+1]!=0&&!check[i][j+1])//判断右
       {
        check[i][j+1]=true;
        sum+=square[i][j+1];
        dfs(square,i,j+1,check);
        check[i][j+1]=false;
        sum-=square[i][j+1];
       }

   
     if(square[i][j-1]!=0&&!check[i][j-1])//判断左
     {
      check[i][j-1]=true;
      sum+=square[i][j-1];
      dfs(square,i,j-1,check);
      check[i][j-1]=false;
      sum-=square[i][j-1];
     }
      
  

  if(square[i+1][j]!=0&&!check[i+1][j])//判断下
  {
      check[i+1][j]=true;
      sum+=square[i+1][j];
      dfs(square,i+1,j,check);
      check[i+1][j]=false;
      sum-=square[i+1][j];
      
  }


  if(square[i-1][j]!=0&&!check[i-1][j])//判断上
  {
      check[i-1][j]=true;
      sum+=square[i-1][j];
      dfs(square,i-1,j,check);
      check[i-1][j]=false;
      sum-=square[i-1][j];
      
  }

   
  maximum=max(sum,maximum);//每一次dfs走到底的时候就进行比较,保留最大值
     
}

    int getMaximumGold(vector<vector<int>>& grid) {
        int row=grid.size();
        int line=grid[0].size();
        vector<vector<bool>>check(row+2,vector<bool>(line+2,false));//初始化二维数组
        vector<vector<int>>square(row+2,vector<int>(line+2,0));
        
        for(int i=1;i<row+1;i++)
        {
           for(int j=1;j<line+1;j++)
           {
               square[i][j]=grid[i-1][j-1];
           }
        }

        for(int i=1;i<row+1;i++)
        {
           for(int j=1;j<line+1;j++)
           {
              if(square[i][j]!=0)
              {
                check[i][j]=true;
                sum+=square[i][j];
                dfs(square,i,j,check);
                check[i][j]=false;
                sum=0;//更换起点,路径长度要归零。
              }
           }
        }
      return maximum;
    }
};

注意:黄金矿工和单词搜索不一样,单词搜索只需要找到一个满足题意的路径即可(即找到之后剩下的无需遍历需要return 返回)而黄金矿工需要遍历所有路径来找到最优解,无需return

3.不同路径III

题目链接:不同路径III

解题思路:

  • 递归结束条件:当前位置的元素值为2,若此时可⾛的位置数量num的值为0,则cnt的值加⼀;
cpp 复制代码
class Solution {
public:

int num=0;
int row=0;
int line=0;


bool judge(vector<vector<bool>>&check)
{
    for(int i=1;i<row+1;i++)
        {
           for(int j=1;j<line+1;j++)
           {  
               if(check[i][j]==false)//有格子没走过
               return false;
           }
        }
    return true;//所有格子都走过
}




void dfs(vector<vector<int>>& square,int i,int j,vector<vector<bool>>&check)
{
       if(square[i][j]==2)  //走到终点
       {
            if(judge(check))
            {
                num++;  //路径数量++;
            }
       }


       if((square[i][j+1]==0||square[i][j+1]==2)&&!check[i][j+1])//判断右
       {
          check[i][j+1]=true;
          dfs(square,i,j+1,check);
          check[i][j+1]=false;//恢复现场
       }

       if((square[i][j-1]==0||square[i][j-1]==2)&&!check[i][j-1])//判断左
       {
          check[i][j-1]=true;
          dfs(square,i,j-1,check);
          check[i][j-1]=false;//恢复现场
       }

       if((square[i+1][j]==0||square[i+1][j]==2)&&!check[i+1][j])//判断下
       {
          check[i+1][j]=true;
          dfs(square,i+1,j,check);
          check[i+1][j]=false;//恢复现场
       }



       if((square[i-1][j]==0||square[i-1][j]==2)&&!check[i-1][j])判断上
       {
          check[i-1][j]=true;
          dfs(square,i-1,j,check);
          check[i-1][j]=false;//恢复现场
       }

}


    int uniquePathsIII(vector<vector<int>>& grid) {
        row=grid.size();
        line=grid[0].size();
        int position_row=0;
        int position_line=0;
        vector<vector<bool>>check(row+2,vector<bool>(line+2,false));
        vector<vector<int>>square(row+2,vector<int>(line+2,3));

        for(int i=1;i<row+1;i++)
        {
           for(int j=1;j<line+1;j++)
           {
               square[i][j]=grid[i-1][j-1];
               if(square[i][j]==1||square[i][j]==-1)
               {
                    if(square[i][j]==1)
                    {
                        position_row=i;//找入口的行
                        position_line=j;//找入口的列
                    }
                    check[i][j]=true; //
               }
           }
        }
     

     dfs(square,position_row, position_line,check);
     return num;
    }
};
相关推荐
柠石榴2 分钟前
【练习】力扣热题100 有效的括号
c++·算法·leetcode·职场和发展
0xCC说逆向6 分钟前
Windows图形界面(GUI)-QT-C/C++ - Qt图形绘制详解
c语言·开发语言·c++·windows·qt·mfc·win32
jf加菲猫9 分钟前
3 生成器(Builder)模式
c++·设计模式
情深不寿31717 分钟前
C++----STL(string)
开发语言·c++
boss-dog19 分钟前
C++内存泄露排查
c++·内存泄露
旧物有情27 分钟前
蓝桥杯历届真题 # 数字诗意(C++,Java)
java·c++·蓝桥杯
迪小莫学AI1 小时前
高效解决 LeetCode 2270: 分割数组的方案数
算法·leetcode·职场和发展
egoist20231 小时前
数据结构之顺序结构二叉树(超详解)
c语言·开发语言·数据结构·学习·算法·二叉树·向上/下调整算法
青い月の魔女1 小时前
初识C++(二)
开发语言·c++·笔记·学习
Verdure陌矣1 小时前
C++项目目录结构以及.vscode文件下的文件详解
开发语言·c++·vscode