//模板
public static void dfs(){
if(当前状态==目标状态){
//逻辑处理
return ;
}
for(寻找新状态){
if(合法){
dfs(新状态);
}
}
}
回溯:
向前每一步,标记,不行就回退,并撤销状态
//模板
public static void dfs(){
if(当前状态==目标状态){
//逻辑处理
return ;
}
for(寻找新状态){
if(合法){
//标记状态
dfs(新状态);
撤销状态;
}
}
}
人类的开心程度有高低之分,数字也一样。
给定一个正整数 ,在 的数位之间插入 个加号,使其变成一个表达式,计算得出的结果就是 的一个 级开心程度。
例如 , 时,我们可以往 和 之间插入一个 号,使其变为 ,计算出结果为 。那么 就是 的一个 级开心程度。
给定 ,请你计算出 的 级开心程度的最大值与最小值之差。
输入格式
一行输入两个正整数 n,含义见题面。
输出格式
一行一个整数,表示 的 级开心程度的最大值与最小值之差。
import java.util.Scanner;
public class Startup {
static long max = Long.MIN_VALUE;
static long min = Long.MAX_VALUE;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[] c = sc.next().toCharArray();
int k = sc.nextInt();
StringBuilder str = new StringBuilder();
dfs(0, c, k, str);
System.out.println(max - min);
}
public static void dfs(int u, char[] c, int k, StringBuilder str) {
if (u == c.length) {
if (k == 0) {
String[] s = str.toString().split("\\+");
long res = 0;
for (String x : s) {
res += Long.valueOf(x);
}
max = Math.max(max, res);
min = Math.min(min, res);
}
return ;
}
// 递归添加当前字符,不加 '+' 符号
str.append(c[u]);
dfs(u + 1, c, k, str);
str.deleteCharAt(str.length() - 1); // 回溯
// 如果k大于0并且可以加'+',则递归添加当前字符并加上'+'符号
if (k > 0 && u < c.length - 1) {
str.append(c[u]);
str.append('+');
dfs(u + 1, c, k - 1, str);
str.deleteCharAt(str.length() - 1);
str.deleteCharAt(str.length()-1);// 回溯删除最后的'+'
}
}
}
路径之谜
小明冒充 X 星球的骑士,进入了一个奇怪的城堡。
城堡里边什么都没有,只有方形石头铺成的地面。
假设城堡地面是 n×n 个方格。如下图所示。
按习俗,骑士要从西北角走到东南角。可以横向或纵向移动,但不能斜着走,也不能跳跃。每走到一个新方格,就要向正北方和正西方各射一箭。(城堡的西墙和北墙内各有 n 个靶子)同一个方格只允许经过一次。但不必走完所有的方格。如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?有时是可以的,比如上图中的例子。
本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)
输入描述
第一行一个整数 N (0≤N≤20),表示地面有 N×N 个方格。
第二行 N 个整数,空格分开,表示北边的箭靶上的数字(自西向东)
第三行 N 个整数,空格分开,表示西边的箭靶上的数字(自北向南)
import java.util.*;
public class Main{
static int[] col;
static int[] row;
static boolean[][] st;
static ArrayList<Integer> arr;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
col=new int[n];
row=new int[n];
for(int i=0;i<n;i++) col[i]=sc.nextInt();//横
for(int j=0;j<n;j++) row[j]=sc.nextInt();//竖
st=new boolean[n][n];
arr=new ArrayList<>();
arr.add(0);
col[0]--;
row[0]--;
st[0][0]=true;
dfs(0,0,n);
for(int i=0;i<arr.size();i++){
System.out.print(arr.get(i)+" ");
}
}
public static boolean dfs(int x,int y,int n){
//最终的结果判断
if(x==n-1&&y==n-1){
for(int i=0;i<n;i++){
if(col[i]!=0||row[i]!=0) return false;
}
//如果通过了上面的判断,说明符合条件,最终找到了路径,返回true
return true;
}
//一整个搜索的过程
int[] dx={1,-1,0,0};
int[] dy={0,0,1,-1};
for(int i=0;i<4;i++){
int x1=x+dx[i];
int y1=y+dy[i];
//判断不满足的情况并排除,有点像剪枝
if(x1<0||x1>=n||y1<0||y1>=n||st[x1][y1]) continue;
if(row[x1]<=0||col[y1]<=0) continue;
//能走到这一步说明是合法的一个点,改变,更新相关的值
st[x1][y1]=true;
row[x1]--;
col[y1]--;
arr.add(x1*n+y1);
//如果在这个点的深度搜索之后,得到了最终的路径就返回true,否则就回溯
if(dfs(x1,y1,n)) return true;
st[x1][y1]=false;
row[x1]++;
col[y1]++;
arr.remove(arr.size()-1);
}
return false;
}
}
回溯:
-
回溯的需求:
- 递归搜索:回溯通过递归的方式,尝试从当前位置
(x, y)向四个方向(上下左右)探索。如果当前路径符合所有的约束条件,继续往下走;如果不符合,撤回(回溯)到上一个位置,重新尝试其他路径。 - 状态空间的探索:回溯可以有效地探索所有可能的路径。通过在每一步递归时不断选择不同的方向,程序能够遍历所有的路径组合,直到找到一条符合条件的路径,或者确认没有符合条件的路径。
- 回溯的撤销操作:每次递归深入一层后,都会记录当前的选择,并更新状态(例如标记当前的位置已访问,并更新行列的可访问次数)。当递归返回时,程序需要撤销这些操作,恢复到之前的状态,从而尝试新的路径。
- 递归搜索:回溯通过递归的方式,尝试从当前位置
回溯的实现:
1. 递归进入:
- 通过
dfs(x, y, n)方法来进行递归搜索路径。 - 如果当前的位置
(x, y)是目标位置(n-1, n-1),程序会检查是否所有的行和列都已经按照要求被访问了。如果所有要求满足,返回true,表示找到了一条符合要求的路径。 - 如果当前位置不是目标位置,程序会继续尝试在四个方向上走。
2. 四个方向的选择:
- 程序通过
dx和dy数组定义了四个方向的相对坐标变化(右、左、下、上)。 - 对于每个方向,程序会判断:
- 是否越界。
- 是否已经访问过该位置。
- 是否还可以访问该位置(即该位置所在的行列是否还有可用的访问次数)。
3. 选择路径:
- 如果可以选择某个位置作为下一个步骤,程序会标记该位置已访问,并更新行列的可用次数。
- 然后递归地进入这个新的位置,继续搜索下一个位置。
4. 回溯(撤销操作):
- 如果在某个方向尝试失败(即没有找到符合条件的路径),程序会撤销这一步的选择:
- 恢复该位置的访问状态,即将
st[x1][y1]恢复为false。 - 恢复该位置所在行列的可用访问次数。
- 从路径中移除当前的位置。
- 恢复该位置的访问状态,即将
- 这样,程序可以回到上一个位置,继续尝试其他可能的方向。
为什么要回溯:
- 路径选择的可变性:在探索路径时,每个位置可以选择的方向很多,而每个方向又有不同的条件限制(例如行列的可用次数、是否越界、是否已访问等)。这些条件和选择导致了路径的巨大可变性,而回溯恰好适合这种需要探索多个路径的情境。
- 符合条件的路径很少:在大多数情况下,路径并不直接就能符合所有的约束条件(比如每行每列访问的次数、是否越界等),需要在遍历过程中不断地尝试不同的路径,直到找到一条符合条件的路径为止。
- 撤销操作的必要性:如果当前路径选择不符合条件,必须撤销当前选择并回到上一个状态,重新选择其他路径。回溯正是通过这种撤销操作来处理无解情况或寻找其他解的过程。
浙公网安备 33010602011771号