回溯算法
什么是回溯法?
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
用回溯算法解决问题的一般步骤:
1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。
2 、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。
3 、以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
基本思想
从一条路往前走,能进则进,不能进则退回来,换一条路再试。
能解决哪些问题?
- 排列、组合(子集、幂集、字符全排列)。
-
二维数组下的DFS搜索(黄金矿工、数独、装载问题、0-1背包问题、旅行售货员问题、八皇后问题、迷宫问题、图的m着色问题)
- 数组、字符串,给定一个特定的规则,尝试搜索迭代找到某个解。
回溯的解空间
回溯算法有两种常见的解空间模型,分别对应数学中的两种暴力思想,组合以及排列。其中子集问题,对应数学中的组合问题。排列问题对应数学中的排列问题。
解数独
数独,是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。
数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”
利用回溯算法解数独。思路如下:
1,从0行0列开始,依次往里面填入1-9的数字;
2,然后判断填入这个数字后,该数字对应的行,列和九宫格是否满足不重复的条件;
3,如果当前填入的数字满足,就继续填入下一个数字,下一个数字又从1-9中尝试,如果有满足的数字就说明该数字可用,如果没有,则将该数字又重新置为空格,如此循环往复;
4,如果将所有的数字都尝试了还是没有合适的额,那说明本问题无解,返回false;
1 /* 2 *java 递归 3 */ 4 public class ShuduPro { 5 private int[][] sudoku; 6 public ShuduPro(int[][] sudoku) { 7 this.sudoku = sudoku; 8 } 9 public static void main(String[] args) { 10 int[][] sudoku={ 11 {7, 0, 0, 0, 0, 0, 0, 0, 9}, 12 {1, 4, 0, 3, 0, 9, 0, 0, 6}, 13 {0, 0, 0, 0, 0, 0, 5, 1, 0}, 14 {0, 0, 0, 0, 0, 0, 0, 0, 0}, 15 {0, 0, 2, 0, 8, 1, 0, 0, 0}, 16 {0, 0, 9, 0, 2, 0, 8, 0, 0}, 17 {0, 0, 0, 0, 0, 0, 0, 0, 0}, 18 {0, 2, 8, 5, 0, 6, 9, 0, 0}, 19 {0, 0, 0, 1, 0, 0, 3, 0, 2} 20 }; 21 ShuduPro sudu = new ShuduPro(sudoku); 22 sudu.backTrace(0,0); 23 } 24 private void backTrace(int i, int j) { 25 //完成,打印数组 26 if(i==8 && j==9){ 27 print_sudoku(); 28 return; 29 } 30 //判断是否到列尾,到列尾没到行尾,就换行 31 if(j == 9){ 32 i++; 33 j=0; 34 } 35 36 //如果是空格就填值 37 if (sudoku[i][j] == 0){ 38 for (int n = 1; n <=9; n++){ 39 //判断空格中填任一个数是否符合规则 40 if(check_repeat(i,j,n)){ 41 /* 42 *赋值 43 * 进入下一个空格 44 * 初始化该空格 45 */ 46 sudoku[i][j] = n; 47 backTrace(i,j+1); 48 sudoku[i][j]=0; 49 } 50 } 51 }else{ 52 backTrace(i,j+1); 53 } 54 } 55 56 /** 57 * 58 * @param row 行号 59 * @param col 列号 60 * @param temp 赋的值 61 * @return 62 */ 63 private boolean check_repeat(int row, int col, int temp) { 64 //判断所在行和列是否有重复数字 65 for (int i=0; i < 9; i++){ 66 if(sudoku[row][i] == temp || sudoku[i][col] == temp){ 67 return false; 68 } 69 } 70 //判断所在小九宫格中是否有重复 71 int tempRow = (row / 3) * 3; 72 int tempCol = (col / 3) * 3; 73 for (int i = 0; i < 3; i++){ 74 for (int j = 0; j < 3; j++){ 75 if(sudoku[tempRow + i][tempCol + j] == temp){ 76 return false; 77 } 78 } 79 } 80 return true; 81 } 82 83 //打印矩阵 84 private void print_sudoku() { 85 for (int i = 0; i < 9; i++){ 86 for (int j = 0; j < 9; j++){ 87 System.out.print(sudoku[i][j]+" "); 88 } 89 System.out.println(" "); 90 } 91 System.out.println(" "); 92 } 93 94 }
解数独结果
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?