深搜、回溯、剪枝

深度优先搜索DFS

  • 2.1 无死角搜索I
    • 数独游戏
    • 部分和
    • 水洼数目
  • 2.2 回溯和剪枝
    • n皇后问题
    • 素数环
    • 困难的串
  • 小结
  • 一些使用

2.1 无死角搜索I

数独游戏

你一定听说过“数独”游戏。
如下图所示,玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个同色九宫内的数字均含1-9,不重复。
数独的答案都是唯一的,所以,多个解也称为无解。
本图的数字据说是芬兰数学家花了3个月的时间设计出来的较难的题目。但对会使用计算机编程的你来说,恐怕易如反掌了。
本题的要求就是输入数独题目,程序输出数独的唯一解。我们保证所有已知数据的格式都是合法的,并且题目有唯一的解。
格式要求,输入9行,每行9个数字,0代表未知,其它数字为已知。
输出9行,每行9个数字表示数独的解。

输入:
005300000
800000020
070010500
400005300
010070006
003200080
060500009
004000030
000009700程序应该输出:
145327698
839654127
672918543
496185372
218473956
753296481
367542819
984761235
521839764再例如,输入:
800000000
003600000
070090200
050007000
000045700
000100030
001000068
008500010
090000400程序应该输出:
812753649
943682175
675491283
154237896
369845721
287169534
521974368
438526917
796318452
import java.util.Scanner;public class dfs1_数独 {public static void main(String[] args) {// 输入Scanner sc = new Scanner(System.in);char[][] table = new char[9][];for (int i = 0; i < 9; i++) {table[i] = sc.nextLine().toCharArray();}dfs(table, 0, 0);}public static void dfs(char[][] table, int x, int y) {// x,y为当前所在位置// 到达边界if (x == 9) {print(table);System.exit(0);}// 若当前位置没有填数,则挑选符合条件的数进行填入if (table[x][y] == '0') {for (int i = 1; i <= 9; i++) { // 1~9数字中挑if (check(table, x, y, i)) { // 判断i是否符合要求table[x][y] = (char) (i + '0');dfs(table, x + (y + 1) / 9, (y + 1) % 9);}}table[x][y] = '0'; // 回溯} else { // 若当前位置已有数字,跳过进入下一个数字dfs(table, x + (y + 1) / 9, (y + 1) % 9); // 处理下一个状态}}private static void print(char[][] table) {for (int i = 0; i < 9; i++) {System.out.println(new String(table[i]));}}private static boolean check(char[][] table, int x, int y, int k) {// 所在行、列是否有数字ifor (int j = 0; j < 9; j++) {if (table[x][j] == (char) (k + '0'))return false;if (table[j][y] == (char) (k + '0'))return false;}// 检查小九宫格for (int l = (x / 3) * 3; l < (x / 3 + 1) * 3; l++) {for (int m = (y / 3) * 3; m < (y / 3 + 1) * 3; m++) {if (table[l][m] == (char) (k + '0'))return false;}}return true;}
}

注意一行一行递归是怎么实现的,以及点的小九宫格是怎么实现的

部分和

给定整数序列a1,a2,…,an,判断是否可以从中选出若干数,使它们的和恰好为k.

1≤n≤20
-10^8≤ai≤10^8
-10^8≤k≤10^8

样例:

输入:
n=4
a={1,2,4,7}
k=13输出:
Yes (13 = 2 + 4 + 7)

与非空子集的做法类似

import java.util.ArrayList;
import java.util.Scanner;public class dfs2_部分和 {private static int kk;public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] a = new int[n];for (int i = 0; i < n; i++) {a[i] = sc.nextInt();}int k = sc.nextInt();kk = k;dfs(a, k, 0, new ArrayList<Integer>());}private static void dfs(int[] a, int k, int cur, ArrayList<Integer> ints) {// 出口if (k == 0) {System.out.print("Yes (" + kk + " = ");int size = ints.size();for (int i = 0; i < size; i++) {System.out.print(ints.get(i) + (i == size - 1 ? "" : " + "));}System.out.print(")");System.exit(0);}if (k < 0 || cur == a.length)return;dfs(a, k, cur + 1, ints); // 不选当前cur这个数// 选cur这个数ints.add(a[cur]);int idx = ints.size() - 1; // 当前cur加入ints所处的位置dfs(a, k - a[cur], cur + 1, ints);ints.remove(idx); // 回溯}
}

水洼数目

有一个大小为 N*M 的园子,雨后积起了水。八连通的积水被认为是连接在一起的。请求出园子里总共有多少水洼?(八连通指的是下图中相对 W 的*的部分)

***
*W*
***

限制条件: N, M ≤ 100

样例:

输入
N=10, M=12

园子如下图('W’表示积水, '.'表示没有积水)

W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

输出

3

拓展下一个状态点时,将该状态点由 ‘ w ’ 转为 ’ . ',防止搜索时往回走

import java.util.Scanner;public class dfs3_水洼数目 {private static int n;private static int m;public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();char[][] a = new char[n][];for (int i = 0; i < n; i++) {a[i] = sc.next().toCharArray();}int cnt = 0; // 计数for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (a[i][j] == 'W') {dfs(a, i, j);cnt++; // 该次搜索成功,连通数加1}}}System.out.println(cnt);}private static void dfs(char[][] a, int i, int j) {// 将‘w’转为‘.’,避免往回搜索造成死循环a[i][j] = '.';// 走下一步for (int k = -1; k < 2; k++) {for (int l = -1; l < 2; l++) {if (k == 0 && l == 0) // 当前位置,不用搜索continue;// i为行,j为列,下一步搜索行要>0、<=n-1,列要>0、<=m-1if (i + k >= 0 && i + k <= n - 1 && j + l >= 0 && j + l <= m - 1) {if (a[i + k][j + l] == 'W')dfs(a, i + k, j + l);}}}}
}

2.2 回溯和剪枝

n皇后问题

请设计一种算法,解决著名的n皇后问题。这里的n皇后问题指在一个n*n的棋盘上放置n个棋子,使得每行每列和每条对角线上都只有一个棋子,求其摆放的方法数。

给定一个int n,请返回方法数,保证n小于等于15

public class dfs4_n皇后问题 {private static int n;private static int[] rec;private static int cnt;public static void main(String[] args) {n = 4;rec = new int[8];dfs(0);System.out.println(cnt);}// 一行一行的试探private static void dfs(int row) {// 出口if (row == n) {cnt++;return;}// 依次尝试在某列上放一个皇后for (int col = 0; col < n; col++) {boolean flag = true;// 检验这个皇后是否和之前已经放置的皇后有冲突,checkfor (int i = 0; i < row; i++) {if (rec[i] == col || i + rec[i] == row + col || rec[i] - i == col - row) {flag = false;break;}}/* =======这里可以认为是剪枝======= */// 这一行的这一列可以放if (flag) {rec[row] = col;dfs(row + 1);// rec[row]=0; //恢复原状,这种解法这里是否恢复状态都行,因为check都是check之前的行}}}
}

注意:

x - y 相同,彼此在彼此正对角线上

x + y 相同,彼此在彼此负对角线上

素数环

题源

【算法很美】深入递归 (下)深度优先搜索DFS问题相关推荐

  1. C语言递归实现深度优先搜索DFS算法(附完整源码)

    C语言递归实现DFS算法 完整Graph.h 头文件 完整Graph.c 源文件文件 完整dfs_recursive.c 源文件(main测试函数) 完整Graph.h 头文件 #include &l ...

  2. 算法很美:水洼数(dfs)深搜

    题目描述 Descriptions: 由于近日阴雨连天,约翰的农场中中积水汇聚成一个个不同的池塘,农场可以用 N x M (1 <= N <= 100; 1 <= M <= 1 ...

  3. 【算法入门】深度优先搜索(DFS)

    深度优先搜索(DFS) [算法入门] 郭志伟@SYSU:raphealguo(at)qq.com 2012/05/12 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍 ...

  4. 深度优先搜索(DFS) 总结(算法+剪枝+优化总结)

    深度优先搜索(DFS) 总结(算法+剪枝+优化总结) 本文中会引用部分实例.文献资料来自不同的作者之手,由于资料整理比较困难,转载地址不在文中列举.如有侵权请联系我更换或删除!对于提供题解思路的各位大 ...

  5. c语言中穷竭算法,hihocoder#1054 : 滑动解锁(深度优先搜索)

    描述 滑动解锁是智能手机一项常用的功能.你需要在3x3的点阵上,从任意一个点开始,反复移动到一个尚未经过的"相邻"的点.这些划过的点所组成的有向折线,如果与预设的折线在图案.方向上 ...

  6. 算法很美——数学问题

    算法很美--数学问题 题1:天平称重 问题描述: 用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量. 砝码重量分别是1,3,9,27,81--3的指数次幂,每种重量砝码只有一个 则它们可以 ...

  7. 算法很美-位运算-找出落单的那个数

    上级目录:算法很美 1. 题目 一个数组里除了某一个数字之外,其他的数字都出现了两次.请写程序找出这个只出现一次的数字. 2. 异或思路 异或的运算是A ^ A=0,也就是说偶数个相同的元素异或,结果 ...

  8. 一文搞定深度优先搜索(DFS)与广度优先搜索(BFS)【含完整源码】

    写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...

  9. C++实现深度优先搜索DFS(附完整源码)

    C++实现深度优先搜索DFS C++实现深度优先搜索DFS完整源码(定义,实现,main函数测试) C++实现深度优先搜索DFS完整源码(定义,实现,main函数测试) #include <al ...

最新文章

  1. UDP收/发广播包原理及步骤
  2. 13个球一个天平,现知道只有一个和其它的重量不同,怎样称才能用三次就找到那个球?...
  3. 基于 gRPC 和 .NET Core 的服务器流
  4. 122. 买卖股票的最佳时机 II golang
  5. jdk1.8安装教程,跟着步骤来 安装失败你来打我
  6. 模拟猜数(POJ2328)
  7. Linux 设备驱动--- 并发 与 竞态 --- atomic_t --- atomic_dec_and_test --- 原子操作
  8. 采用Eclipse中间Maven构建Web项目错误(一)
  9. java 中文网址大全
  10. matlab2017b安装之后点桌面图标黑框闪退
  11. ESP8266使用教程之初识
  12. php中的opendir函数,php中opendir函数的用法详解
  13. 萤石云回放时服务器无响应,萤石云手机回放看不了
  14. 盘点程序员的那些常用网站
  15. OKHttp源码详解_tony_851122
  16. Word自动编号,掌握这几招,再也不用手动敲编号!
  17. print list Reversely
  18. OC 基础 UIControl
  19. Vue3 PC桌面端聊天室|vue3.0+elementPlus仿微信/QQ界面
  20. 解决安装 fireworks、photoshop 时卡在输入账号、手机号处等问题

热门文章

  1. 有必要了解的Subword算法模型
  2. Linux- 系统随你玩之--grep查找文件内容
  3. Hbase基础原理及应用(中篇)
  4. 视线追踪(眼动追踪)领域最常用的200个英文单词
  5. 13张图解分布式系统服务注册与发现机制,给你整明白
  6. 高逼格PPT各种资源站点汇总
  7. 学校计算机主任述职报告,系主任述职报告
  8. android 获取wifi主频,史上最全最详细无线通信频率分配表(绝对收藏)
  9. 二极管基本电路之钳位电路
  10. 总线隔离后如何接地?