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

news/2025/1/15 6:30:17/

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

在这里插入图片描述

核心思想

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

典型应用

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

算法流程

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

优势与不足

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

简单示例(伪代码):

def backtrack(path, options):if 满足结束条件:记录结果returnfor option in options:做选择backtrack(新的路径, 剩余选择)撤销选择

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

1.单词搜索

题目链接:单词搜索

在这里插入图片描述
解题思路:

  • 1.将整个数组向外扩充一环(避免讨论边缘问题
  • 2.进行深度优先搜索
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.黄金矿工

题目链接:黄金矿工

在这里插入图片描述
解题思路:

  • 枚举矩阵中所有的位置当成起点,来⼀次深度优先遍历,统计出所有情况下能收集到的⻩⾦数的最⼤值即可。
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的值加⼀;
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;}
};

在这里插入图片描述


http://www.ppmy.cn/news/1563248.html

相关文章

SQL LAST()

SQL中的LAST()函数是一个用于返回指定列中最后一个记录值的函数。然而&#xff0c;需要注意的是&#xff0c;这个函数并不是SQL标准的一部分&#xff0c;因此并不是所有数据库系统都支持它。具体来说&#xff0c;只有MS Access直接支持LAST()函数【0†source】。 在其他数据库…

fastGpt 本地运行 mongo, 要加 directConnection=true 参数

fastGpt 本地运行 mongo psql用docker的 文件复制 FastGPT\projects\app.env.template 复制为 FastGPT\projects\app.env.local 本地 连接docker的mongo, 要加 directConnectiontrue 参数 MONGODB_URImongodb://myusername:mypasswordlocalhost:27017/fastgpt?authSourceadmi…

Java中的反射机制及其应用场景

目录 什么是Java反射机制&#xff1f; 工作原理 主要应用场景 注意事项 总结 什么是Java反射机制&#xff1f; Java反射机制是一种强大的工具&#xff0c;它允许程序在运行时访问、检查和修改其本身的类和对象的信息。通过反射&#xff0c;开发者可以在不知道类的具体实现…

机器学习与人工智能的关系

机器学习与人工智能的关系 一、人工智能二、机器学习2.1 机器学习与人工智能的关系2.2 机器学习的本质 三、其他玩艺 曾几何时&#xff0c;人工智能还是个科幻名词&#xff0c;仿佛只属于未来世界。如今&#xff0c;它已经渗透到了我们生活的方方面面&#xff0c;成为顶流。我们…

Ubuntu上,ffmpeg如何使用cuda硬件解码、编码、转码加速

本文使用 Ubuntu 环境。Ubuntu 直接使用 APT 安装的就支持 CUDA 加速。本文使用这样下载的版本进行演示&#xff0c;你自己编译或者其他源的版本可能会不同。 ffmpeg 的一些介绍&#xff0c;以及 macOS 版本的 ffmpeg 硬件加速请见《macOS上如何安装&#xff08;不需要编译安装…

自动化日常任务:使用Python和PyAutoGUI打开记事本并保存文本

自动化日常任务&#xff1a;使用Python和PyAutoGUI打开记事本并保存文本 概述准备工作效果代码 概述 在日常工作中&#xff0c;我们经常会遇到一些重复性的任务&#xff0c;这些任务虽然简单&#xff0c;但却耗费了大量时间。幸运的是&#xff0c;随着自动化技术的发展&#x…

设计模式中的代理模式

在Java中&#xff0c;代理模式&#xff08;Proxy Pattern&#xff09;可以通过静态代理和动态代理两种主要方式实现。 一、静态代理模式 在编译时就已经确定了代理类和被代理类的关系。 代理类和目标对象通常实现相同的接口或继承相同父类。 缺点是对于每个需要代理的目标对象…

在 Ubuntu 上安装和配置 Redis

在 Ubuntu 上安装和配置 Redis&#xff0c;并使用发布-订阅&#xff08;Pub/Sub&#xff09;功能&#xff0c;可以按照以下步骤进行&#xff1a; 一、安装 Redis 1. 更新包列表 首先&#xff0c;更新本地的包列表以确保获取到最新的软件包信息&#xff1a; sudo apt update…