竞赛算法–深入递归(上)(DFS、回溯、剪枝等)
竞赛算法–深入递归(下)(DFS、回溯、剪枝等)
2. 深度优先搜索DFS–Depth-First Search
dfs:一条路走到黑
bfs:所有路口看一遍
2.1 无死角搜索 I
- 数独游戏
- 部分和(挑战程序设计竞赛)
- 水洼数目
2.1.1 数独游戏
题目描述:
题目分析及代码:
- 伪代码分析
dfs(table , x, y){ // table为数组 , x,y为坐标
if(x==9){
print(table);
System.exit(0);
}
if(table[x][y] == '0'){
// 选1-9之间的合法数字填到 x,y这个位置
for( i= 1 .... 9){
boolean res = check(table , x,y,i); //检查数字是否合法
if(res){
table[x][y] = i ; // 转移到下一个状态
// x + (y+1)/9 代表y达到最大索引8时,换行即 x+1
// (y + 1) % 9 代表y的索引,达到最大索引8时,换行后 从0开始
dfs(table , x + (y+1)/9 ,(y+1)%9);
}
}
table[x][y] = 0; // 回溯
}else{
// 继续找下一个需要处理的位置
dfs(table , x + (y+1)/9 ,(y+1)%9 );
}
}
完整代码:
public class Main{
public class Main(String [] args){
Scanner in = new Scanner (System.in);
int [][] table = new char[9][9];
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
table[i][j] = in.nextInt();
}
}
solve(table,0,0);
}
private static void solve(int[][] table , int x,int y){
if(x==9){
print(table);
System.exit(0);
}
if(table[x][y] == 0){ // 虚位以待
for(int k = 1;k<10;k++){
if(check(table,x,y,k)){
table[x][y] = k;
solve(table, x + (y+1)/9 ,(y+1)%9);
}
}
table[x][y] = 0; // 回溯;
}else{
solve(table, x + (y+1)/9 ,(y+1)%9);
}
}
private static void print(int[][] table){
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
System.out.print(table[i][j]);
}
System.out.println();
}
}
private static boolean check(char[][] table,int i , int j ,int k){
//检查同行同列
for(int l = 0 ; l < 9 ; l++){
if(table[i][l] == k ) return false;
if(table[l][j] == k ) return false;
}
// 检查小九宫格
for(int l = (i/3)*3 ; l < (i/3+1)*3 ; l++ ){
for(int m = (j/3)*3 ; m<(j/3)*3; m++){
if(table[l][m] == k) return false;
}
}
return true;
}
}
2.1.2 部分和
题目描述:
- 给定整数序列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)
题目分析+题解代码:
- 方法一:类似于求子串的问题
用到深入递归1.2.2的非空子集问题-二进制解法
在这里插入代码片
- 方法二: dfs
import java.util.*;
public class Main{
static int kk = 0;
public static void main(String args[]){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int [] a = new int[n];
for(int i=0;i<n;i++){
a[i] = in.nextInt();
}
int k = in.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.println("Yes ("+kk+"=");
int size = ints.size();
for(int i=0;i<size;i++){
System.out.print(ints.get(i)+(i==size-1?"":"+"));
}
System.out.println(")");
System.exit(0);
}
if(k<0 || cur == a.length) return;
dfs(a,k,cur+1,ints);// 不要cur这个元素
ints.add(a[cur]);
int index = ints.size()-1;
dfs(a,k-a[cur],cur+1,ints);
ints.remove(index); // 回溯
}
}
2.1.2 水洼数目
题目描述:
import java.util.Scanner;
public class Main{
static int n=0,m=0;
public static void main(String [] args){
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
char[][] a = new char[n][m];
for(int i=0;i<n;i++){
a[i] = in.nextLine().toCharArray();
}
int count = 0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i][j]=='w'){
dfs(a,i,j); // 清除一个水洼
count++;
}
}
}
System.out.println(count);
}
private static void dfs(char[][] a , int i,int j){
a[i][j] = '.';
for(int k =-1;k<2;k++){ // -1 , 0, 1
for(int l =-1;l<2;l++){ // -1 , 0, 1
if(k==0 && l==0) continue;
if( 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);
}
}
}
}
}
}