1. 回溯
1.1 回溯的应用场景
- 递归代表开启一个分支,如果希望这个分支返回后某些数据恢复到分支开启以前的状态以便重新开始,则需要用到回溯
1.2 典型例题
1.2.1 全排列
public class Q9_全排列 {
public static void main(String[] args) {
String s = "231564";
System.out.println(getPermutation(s));
System.out.println(getPermutation(s, s.length()-1));
System.out.println(getPerm(s));
}
public static ArrayList<String> res = new ArrayList<>();
public static ArrayList<String> getPerm(String s){
char[] arr = s.toCharArray();
getPerm(arr, 0);
return res;
}
private static void getPerm(char[] arr, int i) {
if(i == arr.length){
res.add(new String(arr));
}
for (int j = i; j < arr.length; j++) {
swap(arr, i, j);
getPerm(arr, i+1);
swap(arr, i, j);
}
}
private static void swap(char[] arr, int i, int j){
char temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
1.2.2 数独游戏
public class Q8_数独游戏 {
public static void main(String[] args) {
int[][] table = {
{0,0,5,3,0,0,0,0,0},
{8,0,0,0,0,0,0,2,0},
{0,7,0,0,1,0,5,0,0},
{4,0,0,0,0,5,3,0,0},
{0,1,0,0,7,0,0,0,6},
{0,0,3,2,0,0,0,8,0},
{0,6,0,5,0,0,0,0,9},
{0,0,4,0,0,0,0,3,0},
{0,0,0,0,0,9,7,0,0}
};
dfs(table, 0, 0);
}
public static void dfs(int[][] table, int x, int y){
if(x==table.length){
for (int[] ints : table) {
System.out.println(Arrays.toString(ints));
}
System.exit(0);
}
if(table[x][y] == 0){
for (int i = 1; i < 10; i++) {
if(check(table, x, y, i)){
table[x][y] = i;
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 boolean check(int[][] table, int x, int y, int i) {
for (int j = 0; j < table[0].length; j++) {
if(table[x][j] == i || table[j][y] == i){
return false;
}
}
for (int j = (x/3)*3; j < (x/3+1)*3; j++) {
for (int k = (y/3)*3; k < (y/3+1)*3; k++) {
if(table[x][y] == i){
return false;
}
}
}
return true;
}
}
1.2.3 部分和
public class Q12_部分和 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,9};
int target = 10;
ArrayList<List<Integer>> addSum = addSum(arr, target);
System.out.println(addSum);
dfs(arr, target, 0, new ArrayList<>());
}
public static void dfs(int[] arr, int k, int cur, ArrayList<Integer> res){
if(k == 0){
System.out.println(res);
return;
}
if(k < 0 || cur == arr.length) return;
dfs(arr, k, cur+1, res);
res.add(arr[cur]);
int index = res.size()-1;
dfs(arr, k-arr[cur], cur+1, res);
res.remove(index);
}
}
2. 剪枝
2.1 应用场景
- DFS时,如果已经明确重当前状态无论如何都无法解决问题,就应该中断,不用再继续往下搜,这种方式称为剪枝
- 数独、部分和里面都有剪枝
2.2 常见例题
2.2.1 n皇后问题
public class Q11_n皇后问题 {
static int n;
static int cnt;
static int[] rec;
public static void main(String[] args) {
for (int i = 1; i < 11; i++) {
n = i;
rec = new int[n];
dfs(0);
System.out.println(n + "=" + cnt);
cnt=0;
}
}
public static void dfs(int row){
if(row == n){
cnt++;
return;
}
for (int col = 0; col < n; col++) {
boolean ok = true;
for (int i = 0; i < row; i++) {
if(rec[i]==col || i+rec[i]==row+col || i-rec[i]==row-col){
ok = false;
break;
}
}
if(ok){
rec[row] = col;
dfs(row+1);
rec[row] = 0;
}
}
}
}
2.2.2 素数环
public class Q12_素数环 {
public static void main(String[] args) {
for (int n = 1; n < 10; n++) {
int[] rec = new int[n];
rec[0] = 1;
dfs(n, rec, 1);
System.out.println("---------");
}
}
private static void dfs(int n, int[] rec, int cur) {
if(cur == n && isP(rec[0]+rec[n-1])){
System.out.println(Arrays.toString(rec));
return;
}
for (int i = 2; i <= n; i++) {
if(check(rec, i, cur)){
rec[cur] = i;
dfs(n, rec, cur+1);
rec[cur] = 0;
}
}
}
private static boolean check(int[] rec, int i, int cur) {
for (int e : rec) {
if(e==i || !isP(rec[cur-1]+i)){
return false;
}
}
return true;
}
private static boolean isP(int i) {
for (int j = 2; j*j <= i; j++) {
if(i % j == 0) return false;
}
return true;
}
}